목차
1. GitHub 저장소
2. 새로운 요구사항
3. 리팩터링
4. 생각하기
5. 셀프 회고
1. GitHub 저장소
GitHub: https://github.com/yeon-06/java-chess/tree/step2
Pull Request: https://github.com/woowacourse/java-chess/pull/366
1~3단계 학습로그: https://yeonyeon.tistory.com/212
2. 새로운 요구사항
- 웹 UI 및 DB 연동
- UI: Spark
- DB: MySQL
- 콘솔과 웹 진행 둘 다 가능
- 방 번호를 통해 게임방에 입장 가능
3. 리팩터링
3-1. 상태 패턴 제거
- 뷰를 완전 분리하기 위해서 불필요한 메서드 계속 늘어남
- BiConsumer 등을 이용해 View 메서드를 호출시킬 수 있지만 View와 완전히 분리된 것은 아니라고 판단
- 현재 특정 조건이 나타날 때까지 계속 request를 받는 형태로 구현
웹을 적용하게 된다면 한번의 request -> 한번의 response를 무조건 받아야함 (결과가 에러일지어도)
👉 웹을 적용하는 경우 상태 패턴이 득보다 실이 많다고 판단하여 제거
3-2. try-with-resources 사용하기
이펙티브 자바 item 9: try-finally 보다는 try-with-resources를 사용하라
- AS-IS
- PreparedStatement를 finally에서 close
- close시 SQLException이 발생할 수 있어 try-catch를 한번더 감싸줌
- 로직이 복잡함
public void updateTurn(Team turn, int id) {
String sql = "update board set turn = ? where id = ?";
PreparedStatement preparedStatement = null;
try {
preparedStatement = connection.prepareStatement(sql);
// preparedStatement 실행 로직
} catch (SQLException e) {
e.printStackTrace();
} finally {
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- TO-BE
- try-with-resources 활용
- try가 종료되는 시점에 AutoCloseable 인터페이스의 close() 메서드가 자동 호출
-> PreparedStatement가 해제됨
public void updateTurn(Team turn, int id) {
String sql = "update board set turn = ? where id = ?";
try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
// preparedStatement 실행 로직
} catch (SQLException e) {
e.printStackTrace();
}
}
3-3. Controller vs Service vs DAO
- Controller: url과 실제 돌아가는 로직을 매핑시켜주는 역할
- Service: 로직이 존재하는 위치 (DAO 실행 포함)
- DAO: DB와 연동해 데이터를 받아옴
각자의 역할이 위와 같다는 생각을 하고 구현
3-4. SQLException에 대해
👉 링크: https://yeonyeon.tistory.com/215
4. 생각하기
4-1. DAO 주입하기
기존에는 Connection을 받아 내부에서 Dao를 생성하게 만들었다.
그리고 스티치가 Dao에 대한 의존성을 유연하게 관리할 수 있게 수정해보자는 제안을 해주셨다.
- 기존: Connection을 받아 내부에서 생성
// AS-IS
private final PieceDao pieceDao;
private final BoardDao boardDao;
public ChessService(Connection connection) {
this.pieceDao = new PieceDaoImpl(connection);
this.boardDao = new BoardDaoImpl(connection);
}
- 수정: 외부에서 생성한 Dao를 주입받아 저장
// TO-BE
private final PieceDao pieceDao;
private final BoardDao boardDao;
public ChessService(PieceDao pieceDao, BoardDao boardDao) {
this.pieceDao = pieceDao;
this.boardDao = boardDao;
}
4-2. 필드가 꼭 필요한지 생각해보기
아래와 같은 Board를 생성해주는 Generator가 존재했다.
Board에는 Map과 Team이 필요하고, 여기서 필요한 Map을 필드로 만들었다.
여기서 스티치가 '해당 변수가 굳이 필드로 관리되어야 할 이유가 있을까요??'라는 의문을 던져주셨다.
// AS-IS
public class BasicBoardGenerator implements BoardGenerator {
private final Map<Position, Piece> board = new HashMap<>();
public Board create() {
initBlackPieces(); // board에 데이터들을 put하는 메서드
initWhitePieces(); // board에 데이터들을 put하는 메서드
return new Board(new HashMap<>(board), Team.WHITE);
}
// ...
}
// TO-BE
public class BasicBoardGenerator implements BoardGenerator {
public Board create() {
Map<Position, Piece> board = new HashMap<>();
initBlackPieces(board);
initWhitePieces(board);
return new Board(board, Team.WHITE);
}
// ...
}
필드일 때는 얕은 복사로 인한 값의 변경 위험성 때문에 매번 new HashMap을 이용했었다.
로직을 바꾼 후로는 신경쓰지 않아도 된다!
4-3. Request와 Response
Request를 네이밍에 사용했다면 dto는 명명에서 제거해도 될 것 같다는 제안을 받았다.
(Request는 흔히 dto로 간주하기 때문에)
👉 MoveRequestDto -> MoveRequest로 변경
4-4. 정적 팩토리 메서드
이전에는 보통 캐싱된 값에 대해 반환할 때만 정적 팩토리 메서드를 사용했다.
이번에는 데이터 가공을 통해 생성하는 경우에서도 사용해보기로 했다.
변경 후 코드가 훨씬 더 깔끔해보이는 것을 볼 수 있다 ㅎㅎ
// AS-IS
public PieceDto(Piece piece, Position position) {
this(piece.getTeam().name().toLowerCase(),
piece.getInfo().getType(),
position.getName());
}
// TO-BE
public static PieceDto of(Piece piece, Position position) {
String team = piece.getTeam().name().toLowerCase();
String type = piece.getInfo().getType();
String positionName = position.getName();
return new PieceDto(team, type, positionName);
}
5. 셀프 회고
리뷰어들의 방학도 보장되어야 한다 생각해서 최대한 일찍 제출하려 했으나 잘 안됐다... 리뷰 한번 받고 머지 당할 각오도 하고 있었다. 정말 정말 정말 감사하게도 스티치가 정성껏 오래오래 리뷰를 남겨주셨다. 오늘 드디어 머지가 됐는데 머지 하시면서까지 공부할거리를 남겨주셨다. 정말 감사와 감동의 눙물..🥺😢 무상태 객체라는 키워드로 한번 공부해보기!
기나긴 체스 미션을 드디어! 마쳤다. 우테코의 꽃이래서 왜...? 레벨1에서 벌써..? 라는 생각을 했는데 생각보다 힘들더라. .. 체스 지긋지긋해 NOoo... 근데 레벨2 때 또 하는 모양이다. 이번엔 Spring을 적용시키겠지...? 잠깐 공부했던거라 자세히는 모르지만 JdbcTemplate 이용하게 될까? Exception 처리가 줄면 코드가 지금보다 좀 더 깔끔해지지 않을까 ㅎㅎㅎ 코드 깔끔해질 생각을 하니 벌써부터 신난다😊
Spring 하니까 생각난건데 인프런에 김영한님 Spring DB 강의가 올라왔더라. 아 예습 말고 복습하려고 했는데 영한님 강의는 못참지;;; JDBC부터 차근차근 설명해주시는 것 같으니까 이건 복습이다^ㅡ^)b 스프링 MVC편 아직 안들었으니까 예습 아님! 진짜 정신 승리 아님! 생각난 김에 결제하러 가야지 💸💸💸
+
구매.완.
'Memo > 우테코 4기' 카테고리의 다른 글
[우테코] Spring 체스 미션 1~2 단계 학습 로그 (2) | 2022.05.02 |
---|---|
[우테코] 레벨1 인터뷰 (2) | 2022.04.24 |
[우테코] 체스 미션 1~3 단계 학습 로그 (4) | 2022.04.01 |
[우테코] 블랙잭 미션 2단계 학습 로그 (2) | 2022.03.20 |
[우테코] 블랙잭 미션 1단계 학습 로그 (0) | 2022.03.15 |