본문 바로가기
Memo/우테코 4기

[우테코] 체스 미션 4~5 단계 학습 로그

by 연로그 2022. 4. 12.
반응형

목차

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 연동
  • 콘솔과 웹 진행 둘 다 가능
  • 방 번호를 통해 게임방에 입장 가능

 


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

 

[Java] 사라진 SQLException

😏 서론 이번에 체스 미션에서 PreparedStatement를 이용해 DB 데이터를 가져왔다. try - catch를 통해 SQLException를 처리하는 코드가 필수적이었는데 한가지 의문점이 들었다. 예전에 진행했던 프로젝트

yeonyeon.tistory.com

 

 


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편 아직 안들었으니까 예습 아님! 진짜 정신 승리 아님! 생각난 김에 결제하러 가야지 💸💸💸

 

 

+

구매.완.

반응형