목차
1. GitHub 저장소
2. 요구사항
3. 공부한 개념들
4. 피드백
5. 셀프 회고
1. GitHub 저장소 🐱💻
1, 2단계 Repository: https://github.com/yeon-06/atdd-subway-map/tree/step1
1, 2단계 Pull Request: https://github.com/woowacourse/atdd-subway-map/pull/190
3단계 Repository: https://github.com/yeon-06/atdd-subway-map/tree/step2
3단계 Pull Request: https://github.com/woowacourse/atdd-subway-map/pull/274
2. 요구사항 🚀
🔻 1단계 요구사항
데이터 형식은 API 문서 에 따른다.
- 지하철 역 관리 API 기능 완성
- 지하철 역 생성 시 이미 등록된 이름으로 요청한다면 에러 응답
- 지하철 역 생성 시 이미 등록된 이름으로 요청한다면 에러 응답
- 지하철 노선 관리 API 구현
- 지하철 노선 등록
- (e) 등록된 이름으로 요청
- 지하철 노선 목록
- 지하철 노선 조회
- (e) 조회된 노선이 없는 경우
- 지하철 노선 수정
- (e) 중복된 이름으로 수정
- 지하철 노선 삭제
- 지하철 노선 등록
- End to End 테스트 작성
🔻 2단계 요구사항
- 데이터를 H2 DB에 저장하기
- H2 DB 설정하기
- 테이블 생성하기
- Spring Bean & Spring JDBC 적용하기
- @Controller, @Service, @Repository 적용
- 예외 @ExceptionHandler로 처리
- JdbcTemplate는 NamedJdbcTemplate 사용
🔻 3단계 요구사항
- 지하철 노선 API 변경
- 지하철 노선은 구간 정보를 포함
- 노선 등록 시 upStationId, downStationId, distance 데이터 추가 입력
- (e) 존재하지 않는 역 이용
- (e) 상행과 하행 역이 동일
- (e) 거리가 0 이하
- 노선 조회 시 구간 정보를 포함
- 구간 API 구현
- 구간 등록
- (e) 거리가 0 이하
- (e) 새로운 역과의 거리가 기존 역과의 거리보다 크거나 같은 경우
- (e) 이미 등록된 구간
- (e) 갈래길 (ex: A역의 상행으로는 B역, C역 두 갈래가 있다)
- (e) 존재하지 않는 역 이용
- (e) 상행과 하행 역이 동일
- 구간 제거
- 중간에 역 제거 시 구간 재배치 필요 (거리는 두 구간의 합으로 설정)
- 구간 등록
3. 공부한 개념들 📚
3-1. Spring의 Transaction 관리
- 트랜잭션이란?
- Spring의 트랜잭션 관리
- AOP란?
- @Transactional이란?
👉 https://yeonyeon.tistory.com/223
3-2. 파라미터를 Optional로 받지 말자
👉 https://yeonyeon.tistory.com/224
3-3. Domain vs Entity
- Domain: 소프트웨터로 해결하고자 하는 문제 영역
- Entity: 정보를 저장할 수 있는 개념 (식별자를 가짐)
3-4. 의존 관계 주입하기
미션 1단계를 통해 의존 관계를 ^직접^ 주입하며 크고 작은 에러를 많이 만났습니다. 그러다 테스트 코드를 위한 메서드를 생성하는 상황(..)까지 이르렀는데 @Component를 활용한 후로 훨씬 편해졌어요. 컴포넌트 어노테이션을 왜 사용하느냐 라고 누가 묻는다면 그 이유 중 하나로 편리한 의존 관계 주입이라고 답할 것 같아요!👍
3-5. Repository vs Dao
- Repository: 객체의 상태를 관리하는 저장소.
- Dao: 데이터 영속성의 추상화. 주로 DB에 접근하기 위해 사용.
👉 결론적으로 Repostiory를 적용하지는 않았다. 다만 리뷰어가 Domain Service라는 새로운 개념을 가르쳐주셨는데 좀 솔깃해서 이 부분에 대해서 공부해봐야겠다.
3-6. @Transactional의 readOnly
이는 단지 '힌트'일 뿐이고 실제 DB를 read-only 트랜잭션으로 생성할지는 모른다.
JDBC 드라이버가 이에 대한 기능을 구현하는 경우에만 지원이 된다.
- Oracle: 지원
- MySQL: 5.6.5 부터 지원
- H2: 미지원
4. 피드백 💡
🙋♀️: 본인(연로그), 👩🏫: 리뷰어(또링)
4-1. 수정에 대한 상태 코드는 어떤 것이 적절한가?
🙋♀️: 저라면 수정된 결과를 응답으로 받아야하면 200, 응답이 불필요하다면 204로 보낼 것 같아요!
👩🏫: 그렇군요! 좋아요😃 보통 PUT에 대한 응답은 200이나 201로 많이 내려요. 리소스가 생성(혹은 변경)되었다는 의미로 200보다는 조금 더 구체적인 201을 사용하기도합니다!
4-2. 생성자 체인 사용하기
- : 생성자에서 다른 생성자를 호출하는 기술
- 코드의 간소화
- 유지 관리가 용이
// AS-IS
public Line(String name, String color) {
this.name = name;
this.color = color;
}
public Line(Long id, String name, String color) {
this.id = id;
this.name = name;
this.color = color;
}
// TO-BE
public Line(String name, String color) {
this.name = name;
this.color = color;
}
public Line(Long id, String name, String color) {
this(name, color);
this.id = id;
}
4-3. 사용자에게 에러 메시지는 보여주지 않아도 될까?
Exception을 처리하기 위해 아래와 같은 코드를 작성했다.
요 부분에서 리뷰어가 한 코멘트를 달아주셨다.
@ExceptionHandler
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handleException(IllegalArgumentException e) {
logger.error(EMPTY_STRING, e);
return e.getMessage();
}
@ExceptionHandler
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void handleException(Exception e) {
logger.error(EMPTY_STRING, e);
}
👩🏫: Exception을 처리하는 경우에 사용자에게 메세지는 내려주지 않아도 괜찮을까요?
🙋♀️: 코드상 의미있는 메시지를 던져준건 IllegalArgumentException 뿐입니다! 만약 의미있는 메시지를 던지는 Exception이 생기면 그때 가서 별도로 처리해줄 것 같아요~ Exception은 예상치 못한 에러가 발생하는 경우 공통으로 처리해주기 위해 생성한 부분입니다. 헌데 이 '예상치 못한' 메시지들을 사용자에게 던져도 괜찮은가?에 대한 의문이 찜찜해서 따로 넘겨주지는 않았습니다!
👩🏫: 좋은 관점이에요! 말씀하신대로 서버 예외 메세지를 그대로 클라이언트에 노출할 필요는 없습니다. 위험하기도 하고, 해당 메세지를 보고 사용자는 어떤 액션을 취해야할지몰라 당황스러울테니까요 ㅎㅎ 그래서 현업에서는(= 제가 담당하는 서비스에서는) '예기치 못한 에러에 대해 일시적인 오류가 발생했습니다. 잠시후 다시 시도해주세요.' 와 같은 메세지를 내려줍니다. 그래야 클라이언트도 서버가 어떤 상황인지 알 수 있으니까요. 😃 지금 지하철 프로젝트에서는 크게 신경 안써도 될 것 같으니 참고만 해주세요. ㅎㅎ
4-4. count보다는 exists
데이터가 존재하는지 검증하기 위해 count(*)를 사용했다. 리뷰어가 jojoldu님 블로그를 주시며 exists를 제안해주셨다. 진짜 exists가 더 빠를지 테스트를 한번 해보았다.
4-5. null과 size 체크
어떤 리스트를 아래와 같이 검사하는 부분이 있다.
value == null || value.size() == 0
리뷰어가 이미 잘 만들어진 util이 있다며 사용을 제안해주셔서 고쳤다.
(내부 코드를 열어보면 위처럼 null과 요소가 존재하는지 체크한다.)
CollectionUtils.isEmpty(value)
🔻 CollectionsUtils.isEmpty() 내부 코드
public static boolean isEmpty(@Nullable Collection<?> collection) {
return (collection == null || collection.isEmpty());
}
5. 셀프 회고 🙋♀️
요번 미션은 기간이 중간에 늘어났음에도 불구하고 촉박하게 진행한 것 같다. 요구 사항은 다 만족했는데 내 마음에 드는 코드인가? 를 물어보면 그렇지는 못한듯😭 다음 미션은 기존 코드에 이어서 진행해서 리팩터링과 테스트 코드 쪽에 좀 욕심을 내고 싶다. 여러가지 테스트에 대해 공부해보고 다양한 시도를 해보고자 한다😄
슬슬 요구사항 충족하기에 급해서 공부 양이 줄어든 느낌이 든다. 체스 때부터 이랬던 것 같기도 하고... 어떤 개념을 공부하고 코드에 적용하기가 힘든 것 같다. 레벨1까지는 Java만 사용했고 어떤 기능을 만들면 IntelliJ가 더 나은 코드를 추천해주거나 내가 직접 구현해왔다. Spring을 사용하니까 많은 기능들을 지원해주지만 그 기능들을 왜 쓰는지 어떻게 만들어진건지 공부하기에 바쁘다. 설계가 잘 짜여진 코드를 짜고 싶은데 공부할게 많아서 어디부터 건드려야할지..😂 테크 살롱 나와서 크루들 이야기 듣는 것만 해도 고칠 점이 백만개는 생긴다😅 열심히 하자 열심히~!
요번 미션에서 많은 질문을 던져주시며 생각할 여지를 많이 남겨주신 페어 주디와 마지막날 밤까지 게더에서 꼼꼼하게 리뷰해주신 리뷰어 또링 너무 감사해요❤
'Memo > 우테코 4기' 카테고리의 다른 글
[우테코] 장바구니 미션 1~2 단계 학습 로그 (2) | 2022.06.14 |
---|---|
[우테코] 지하철 경로 미션 1~2 단계 학습 로그 (2) | 2022.05.29 |
[우테코] Spring 체스 미션 1~2 단계 학습 로그 (2) | 2022.05.02 |
[우테코] 레벨1 인터뷰 (2) | 2022.04.24 |
[우테코] 체스 미션 4~5 단계 학습 로그 (6) | 2022.04.12 |