BEYOND SW 캠프 21기 8회차 & 미니 프로젝트 회고

컨테이너·2025년 11월 16일
post-thumbnail

📝8회차 회고록ㅣBEYOND SW캠프


🖥️ 8회차 학습 (25.11.10 ~ 25.11.14) 기록

알고리즘 끝판왕 그리디, 다이젝스트라, DP를 이번 주에 마무리하고 마침내 스프링을 배우기 위한 준비 단계로 들어섰다. JDBC와 MyBatis 개념과 실습 수업을 들었고, 정말 쉽지 않은 한 주였다. 이번 학습도 아래와 같이 정리했다.

Greedy 알고리즘
Dijkstra 알고리즘
Dynamic Programming 알고리즘
JDBC
동적SQL
MyBatis

사실 알다시피 정말 방대한 분량이다. 100% 이해하지 못하고 지나가는 것들이 정말 많지만, 한 번씩 정리하면서 읽는 것도 도움이 되고 나중에 와서 찾아볼 때도 편해서 정리를 해두는 것이다.

이번 회고록도 지난 금요일부터 진행된 미니 프로젝트에 대한 회고로 진행할 것이다.

👍 KEEP


  • 알고리즘 수업을 통해 한 번씩 훑고 지나가서 좋았다. Greedy, Dijkstra, Dp 작동원리를 다시 보니 정리가 되어 유익했다.
  • 지난 주에 미니 프로젝트를 진행하면서 팀원에게 JDBC 속성 강의를 들었는데, 그것이 이번 주를 위한 훌륭한 예습이 되었다.
  • 도시락을 본격적으로 싸오기 시작했다. 재정적으로 상당히 유리했다. 앞으로도 도시락을 이용할 것이다.
  • 커피가... 맨날 같은 강의장 커피를 마시니 조금씩 질리기 시작했지만 조금 더 참고 먹으려고 한다.

✏️ NEW


Java 콘솔 기반 프로젝트 회고: Konketmon

BeyondSW 21기 두 번째 프로젝트인 콘솔 미니 게임 Konketmon을 만들면서
JDBC, MVC, 계층 분리, 리팩토링, 도메인 설계에 대해 회고해 보겠다.

처음에는 간단한 model-view-controller 구조로 출발했지만,
점점 기능이 늘어나고 책임이 복잡해지면서
service, repository 계층을 추가함으로써 기능적 구조적 분리를 시도했다. 이를 통해 애플리케이션 전체를 리팩토링하게 되었다.

이번 회고록의 목차이다.

  1. 프로젝트 개요
  2. 아키텍처 구조
  3. 포획 로직 및 전투
  4. 리팩토링 전후
  5. 배운점
    정리

1. 프로젝트 개요

Konketmon은 포켓몬 게임에서 영감을 얻은 콘솔 기반 미니 게임이다. 콘켓몬의 모든 종류를 포획하면 승리하고, 그 전에 HP 체력이 전부 떨어진다면, 처음부터 다시 시작해야 한다.
다음은 Konketmon의 기능이다.

  • 회원가입 및 로그인
  • 야생 콘켓몬 조우
  • 전투
  • 포획 확률 공식 기반 포획 시도
  • 포획 후 도감 저장
  • 모든 몬스터 포획 시 게임 승리

이 프로젝트의 목적은 다음 세 가지이다.

  1. Java 기본기 및 객체지향 설계 강화
  2. JDBC를 사용한 “DB 연결 · 트랜잭션 · DAO 분리” 학습
  3. 협업 경험

2. 아키텍처 구조

최종 구조는 다음과 같은 폴더 단위로 정리되었다.

/run
/controller
/view
/model
/service
/repository
/dbconnection

계층구조

run

프로그램 시작점(main). run 파일에서 controller 메인 메소드 호출.

view

모든 콘솔 입출력.
Scanner로 입력 받고 Controller에 전달.

controller

View에서 요청을 받아 Service 호출.
도메인 로직 없이 흐름만 제어.

service

비즈니스 로직 담당 계층.
전투, 포획 확률 계산, 도감 규칙, 회원가입 규칙 등. controller 계층에서 DB 처리 요청을 받아 Repository 계층에서 쿼리문을 받아와 요청 받은 것을 제공해준다.

repository

SQL/JDBC 접근 담당.
PreparedStatement, ResultSet 처리 등 DB 입출력.

dbconnection

JDBC Connection 관리.
싱글턴 기반으로 하나의 Connection을 재사용하도록 한다.


3. 포획 로직 및 전투 규칙

포획 확률 공식

catchRate = BASECATCHRATE + (1 - hpRatio) * 0.7;
  • 기본 확률 BASECATCHRATE : 5%
  • HP가 깎일수록 hpRatio 감소 → catchRate 증가
  • 최종 확률은 5% ~ 95% 사이로 interpolation

추가적으로 게임 기획에서 정한 규칙:

  • HP가 5% 이하이면 포획률 = 95%
  • 포획 실패 시 몬스터 턴으로 전환
  • 포획 성공 시 도감에 저장 후 전투 종료

4. 리팩토링 전후 비교

Before

After

리팩토링 변경사항

  • Controller와 View 내에 혼재되어 있는 Service, Repository 역할을 각각 KonketDex, Konketmon, User 도메인으로 나누었다.

예시 코드

로그인 기능을 예로 들어보자

변경 전 - Controller

public boolean loginUser(String username, String password) throws SQLException {
    PreparedStatement stmt = conn.prepareStatement("SELECT * FROM user WHERE id=? AND pw=?");
    stmt.setString(1, username);
    stmt.setString(2, password);
    ResultSet rs = stmt.executeQuery();
    while (rs.next()) {
        this.user = new User(rs.getString(1),rs.getInt(3),rs.getBoolean(4));
    }
    return this.user != null;
}

↓ ↓ ↓

변경 후 - Controller

public boolean loginUser(String username, String password) throws SQLException {
    return userService.login(username, password);
}

변경 후 - Service

public boolean login(String username, String password) {
    this.user = userRepository.login(this.con, username, password);
    return user != null;
}

변경 후 - Repository

public User login(Connection con, String username, String password) {
    User user = null;
    try (PreparedStatement pstmt = con.prepareStatement("SELECT * FROM user WHERE id=? AND pw=?")) {
        pstmt.setString(1, username);
        pstmt.setString(2, password);
        try (ResultSet rs = pstmt.executeQuery()) {
            while (rs.next()) {
                user = new User(rs.getString(1), rs.getInt(3), rs.getBoolean(4));
            }
        }
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
    return user;
}

위와 같이 Controller 내에 존재하는 모든 메소드를 Controller - Service - Repository 계층으로 나누어서 리팩토링하였다.

  • View: 입력만 받고 Controller 호출
  • Controller: 흐름 제어만 담당
  • Service: 비즈니스 규칙 구현
  • Repository: SQL만 담당

개선점은 아래와 같다.

  • 책임이 명확히 분리된다.
  • 제 3자가 보았을 때 이해가 Before보다 After가 더 쉽다.
  • 트랜잭션 처리 가능한 형태이다.
  • 서비스 로직 재사용 가능하다.

5. 배운 점

5-1. 계층 분리의 필요성

초기 프로젝트 구조는 단순히 model, view, controller만 존재했다.
그러나 기능이 조금만 늘어나자 코드의 결합도가 증가했다.

  • Controller가 SQL을 직접 실행 및 비지니스 로직 계산까지 다 하는 것이 가장 큰 문제점이었 던 것.

→ Service 와 Repository를 추가함으로써 역할 분배, 결합도를 낮추도록 설계.

  • View: 사용자 입출력
  • Controller: 흐름 제어
  • Service: 규칙과 도메인 로직
  • Repository: DB 접근
  • DBCon: 커넥션 관리

이 구조로 재정비하여 각 레이어의 단순화 하였다. 이렇게 하면 추후 제 3자가 비교적 더 쉽게 코드를 이해하는 것과 유지보수 측면에서 좋다.
특히 Service 레이어가 생기면서, 게임 규칙(포획률, 전투 규칙, 승리 조건)을
Controller나 View에 섞지 않고 독립적으로 구현할 수 있었다.


5-2. 리팩토링

리팩토링은 프로젝트를 이끈 팀원의 아이디어로 시작됐다. 작게는 메소드 명과 변수명 부터 시작하여 구조 재정비 및 계층 분리를 했다.

Controller하나와 Repository 하나로 User, Konketmon, Konketdex 도메인의 Service와 DAO 계층을 다루었던 것을 나누자고 한 것이다.

가장 헷갈렸던 파트는 컨트롤러에 있는 User, Konketmon, Konketdex 의 Service, DAO 를 다루는 메소드들을 쪼개고 나누어서 각각 userService, konketmonService, konketdexService 로 보낸 후, Service에서 새로 생성된 메소드들을 통해 요청되는 Data access를 userRepo, konketRepo, konketdexRepo 측에서 접근할 수 있도록 메소드들을 생성하는 작업이다.

리팩토링을 진행하던, 계층 분리를 하던, MVC2 구조를 채택하던, 프로젝트의 전체 구조에 대한 이해가 있어야 한다고 느껴졌다. 프로젝트 전체 구조에 대한 이해를 하려면, 각 기능의 클래스와 생성자, 그리고 사용하는 자료구조와 어떤 곳으로 어떤 객체가 넘어가는지 흐름을 알고 있어야 한다고 느꼈다.

만약 이 구조 리팩터링을 나보고 혼자 하라고 했다면 솔직하게 일주일도 넘게 걸렸을 것이다. 하지만 코드의 구조를 짜고 직접 메소드 하나하나 생성했던 리더 팀원은 빠르게 리팩터링을 마쳤다. 이 시간을 통해 배우기도 많이 배웠지만 내 부족함을 여실히 느꼈고, 프로젝트 경험이 얼마나 개발에 영향을 미치는지 느끼게 되었다.


정리

개발 및 프로젝트 경험이 많이 나는 팀원들과의 협업이었던 만큼, 내가 얼마나 부족한지 느낄 수 있었다. 프로젝트 자체는 스케일이 크지 않았고, 그렇기에 분리된 패키지에서 개별화된 개발을 통한 협업을 하기에는 한계가 있었다. 그런 환경에서 개발을 하다보니 무쌍을 찍는 팀원의 개발을 지켜보며 이해하고 따라가는데 급급했던 모습이 생각난다. 프로젝트 아이디어부터 도메인, 클래스, 각 클래스의 필드 등 사실상 프로젝트의 청사진을 모두 다 그려진 상태에서, 나는 그 것을 이해하면 되는 부분이었지만, 그 것을 이해하는 데에도 부족함이 느껴져서 더 노력하고 프로젝트 경험을 늘려야겠다는 경각심이 생겼다.


💡 PROBLEM


  • 잠 부족 이슈로 정말 피곤했다... 잠을 꼭 6시간 이상 자자
  • 수업을 잘 따라가고 있냐는 생각과 적응을 잘 하고 있는지에 대한 불안감이 엄습해서 갈피를 좀 잃었던 것 같다.
  • 시간이 정말 부족했다. 선택과 집중을 해야 할 때가 왔다.
  • 프로젝트 회고에 작성한 것처럼 경험/지식 부족을 느꼈다.

🪛 TRY


  • 시간이 제한되어 있으니 남은 기간 동안 더 가치 있는 일을 선택해보자.
profile
백엔드

0개의 댓글