군만두의 IT 공부 일지

[Java] 패스트캠퍼스 백엔드 개발 부트캠프 8기 토이 프로젝트 1 DAY5 본문

개발일지/패스트캠퍼스

[Java] 패스트캠퍼스 백엔드 개발 부트캠프 8기 토이 프로젝트 1 DAY5

mandus 2024. 4. 5. 21:13

목차

    📅진행일정: 2024년 4월 1일 ~ 2024년 4월 5일

     

    발표회 준비마무리

     

    ⭐요약


    • 패스트캠퍼스 부트캠프에서 진행한 두 번째 팀 프로젝트. 4명으로 구성된 7 사람들과 함께 5일 동안 여행 여정을 기록과 관리하는 SNS 서비스를 개발함.
    • 5일차에는 Trip과 관련된 클래스에 싱글톤 패턴을 적용함. 그리고 지금까지 진행한 내용을 각자 파트를 분배해 PPT로 작성함. 발표 후에는 PR로 제출할 레포지토리의 README.md 파일 내용을 작성했음.
    • 기능 자체는 단순했지만, Git 작업과 패턴 적용에 있어서 어려움을 겪어서 시간이 많이 걸림. 이 글에서는 우리 팀이 5일 동안 어떻게 함께 고군분투했는지, 그리고 그 과정에서 어떤 성장을 이루었는지 공유하고자 함.
    • 인텔리제이로 처음 자바 프로젝트를 진행한 사람들에게 전체적인 과정을 가이드라인으로 제시해줄 수 있을 것임.

    ⭐토이 프로젝트 1단계 진행 과정


    "여행의 여정 정보를 기록하고 조회하는 Java 애플리케이션"

     

    🚀구현 조건

     

    1. 여행 정보 기록 및 조회(읽기, 쓰기)
    2. 여정 정보와 숙박 정보 기록 및 조회(읽기, 쓰기)
    3. 여행 정보와 특정 여행 정보의 여정 목록을 json 파일 형태로 관리

    RFP에 명확하지 않은 요구사항이 있었음. 위 조건에서 예외 처리와 MVC 패턴, 싱글톤 패턴을 적용하는 것이 처음 목표임.

    1. 프로젝트 요구사항

    과제에서 요구하는 조건에 대한 이해가 필요했음. json 파일을 어떻게 관리할 것인지, 여행과 여정에 대한 json 파일을 분리해야 하는 것인지, 여행 및 여정 정보 조회를 분리할지 하나로 합쳐야 하는지, 여행 및 여정의 수정과 삭제에 대한 기능은 요구사항에 없는데 구현해야 하는지 등 궁금한 사항을 정리해 매니저님에게 질문함.

     

    그렇게 알게 된 내용을 바탕으로 팀원의 역할을 각각 분배함.

    1. 여행 정보 CRUD →
    2. 여정 정보 CRUD
    3. 입출력 및 예외처리
    4. 여행 및 여정 정보 출력

    어떻게 분리할지 고민하다가 기능 단위로 분리함. json에 대해서 연습할 기회를 가지고자 여행과 여정을 분리했음. 비전공자인 팀원도 고려함.

     

    처음에는 읽기와 쓰기 기능만 구현했지만, 주어진 과제 내용과 차별점을 두기 위해 수정과 삭제 기능을 구현하기로 바꿈.

    2. 프로젝트 설정

    🚀프로젝트 세팅

     

    • 언어: Java 17
    • 빌드: maven
    • 모듈: json-simple-1.1.1.jar, lombok
    • 협업 도구: github
    • 소통 도구: discord, notion

    실행 시간이 짧다고 알려진 json-simple 모듈을 maven으로 빌드함. 처음에는 maven으로 하지 않고 json-simple을 모듈로 직접 추가했지만, maven을 사용하니 다운로드나 추가할 필요가 따로 없어 편했음. 그리고 gradle이 maven 보다 장점이 더 많다고 해서, 다음 프로젝트에서는 gradle을 사용해보고 싶음.

     

    리팩토링 과정에서는 getter, setter, toString의 반복을 줄이기 위해서 lombok을 사용함. 소통 도구로는 jira도 사용해 보려고 했으나, 다들 사용이 익숙치 않아 제대로 사용하지 못한 것이 아쉬움.

     

    🚀프로젝트 구성

     

    디렉토리 구조는 MVC 패턴을 적용하려고 했음.

     

    controller 폴더에는 애플리케이션의 로직을 처리하는 클래스가 있고, dto(Data Transfer Object) 폴더에는 데이터 전송 객체가 있음. exception 폴더에는 예외 처리 클래스, jsonManager 폴더에는 JSON 파일 관리를 위한 클래스가 있음. model 폴더에는 애플리케이션의 데이터 모델, resources 폴더에는 정적 리소스, util 폴더에는 유틸리티 클래스, 그리고 view 폴더에는 사용자 인터페이스 관련 클래스가 포함되어 있음. Main.javaTripApplication.java는 애플리케이션의 실행과 관련된 메인 클래스임.

    📦src
     ┣ 📂controller
     ┃ ┣ 📂impl
     ┃ ┃ ┣ 📜ItineraryController.java
     ┃ ┃ ┗ 📜TripController.java
     ┃ ┣ 📜Deletable.java
     ┃ ┗ 📜Saveable.java
     ┣ 📂dto
     ┃ ┣ 📜ItineraryForm.java
     ┃ ┣ 📜ItinerarySaveForm.java
     ┃ ┣ 📜ItineraryUpdateForm.java
     ┃ ┗ 📜TripForm.java
     ┣ 📂exception
     ┃ ┣ 📜DuplicateDateException.java
     ┃ ┣ 📜FileIOException.java
     ┃ ┣ 📜InputEmptyException.java
     ┃ ┣ 📜InputEndException.java
     ┃ ┣ 📜InputRangeException.java
     ┃ ┗ 📜InvalidDateOrderException.java
     ┣ 📂jsonManager
     ┃ ┣ 📜ItineraryJsonManager.java
     ┃ ┗ 📜TripJsonManager.java
     ┣ 📂model
     ┃ ┣ 📜Itinerary.java
     ┃ ┗ 📜Trip.java
     ┣ 📂resources
     ┃ ┗ 📜TripTable.json
     ┣ 📂util
     ┃ ┗ 📜Message.java
     ┣ 📂view
     ┃ ┣ 📂impl
     ┃ ┃ ┣ 📜ItineraryView.java
     ┃ ┃ ┣ 📜MainView.java
     ┃ ┃ ┗ 📜TripView.java
     ┃ ┣ 📜SelectionTask.java
     ┃ ┗ 📜UserInterface.java
     ┣ 📜Main.java
     ┗ 📜TripApplication.java

     

    🚀클래스 다이어그램

     

    RFP의 내용과 동일하게 설계했다가 패턴을 적용하면서 변경함.

    3. Git branch 전략

    유명한 Git Flow를 적용해 보려고 했는데, 현재 우리 실력으로는 브랜치별로 확실하게 기능을 구현하지 못한다면, 프로젝트 구현을 우선 시 하는 게 낫다고 파악함. 원들의 이름으로 브랜치를 생성하고 PR을 올려 머지하는 방식을 사용함.

    - main : product로 배포할 브랜치
    - person1 : 여정 정보 관리 브랜치	// 팀원1
    - person2 : 입출력 및 예외처리 브랜치	// 팀원2
    - person3 : 여행 정보 관리 브랜치	// 팀원3
    - person4 : 여행 및 여정 정보 출력 브랜치	// 팀원4

     

    브랜치 전략에 있어서 아쉬운 점이 있었지만, 다음 프로젝트에서 활용할 수 있도록 공부해야겠음.

    4. 프로젝트 결과

    🚀여행 추가

    🚀여행 삭제 및 수정

    🚀여행 json 파일 생성


    🚀여정 추가

    🚀여정 수정 및 삭제

    🚀여정 json 파일 삭제

    ⭐나의 역할


    이번 과제에서 여행 정보를 관리하는 json CRUD 작업을 맡음. 여행 데이터를 json 파일에 저장하고 읽으며, 필요에 따라 수정하거나 삭제함. 여행 정보의 유효성 검사, 중복 날짜 예외 처리, 파일 입출력 예외 처리 등을 구현했고, 각 여행 정보가 고유 ID를 통해 식별되고 관리되도록 함.

     

    새 여행 정보를 JSON 객체로 생성하고, 해당 객체를 파일 시스템에 새 JSON 파일로 저장하는 코드는 아래와 같이 json-simple 모듈을 사용함.

    JSONObject tripObject = new JSONObject();
    tripObject.put("trip_id", newTripId);
    JSONArray itinerariesArray = new JSONArray();
    tripObject.put("itineraries", itinerariesArray);
    
    try (FileWriter file = new FileWriter(RESOURCE_PATH + newTripId + ".json")) {
        file.write(tripObject.toJSONString());
        file.flush();
    } catch (IOException e) {
        throw new FileIOException("파일 쓰기 중 오류가 발생했습니다.");
    }

     

    예외 처리는 try-catch문을 사용함. 파일을 삭제하는 과정에서 발생할 수 있는 IOException을 포착하고, 이를 사용자 정의 FileIOException으로 변환하여 예외 처리하는 코드인데, 모든 예외 처리를 이런 식으로 하는 것이 맞는지 멘토님께 코드 리뷰를 부탁드려야겠음.

    try {
        Files.deleteIfExists(fileToDeletePath);
        return true;
    } catch (IOException e) {
        throw new FileIOException();
    }

     

    새로운 ID 생성 시 마지막 ID에서 +1하도록 함. 저장된 데이터 중 가장 큰 ID 값을 찾아 1을 더해 새로운 객체에 할당하는데, 삭제를 했을 때 ID 값이 비는 것을 고려한 방식임. 생각나는 방법이 없어서, 이것 보다 좋은 방법이 있었을지 멘토님께 질문을 해야겠음.

    int maxId = 0;
    for (Object o : tripsArray) {
        JSONObject trip = (JSONObject) o;
        int tripId = Math.toIntExact((long) trip.get("trip_id"));
        if (tripId > maxId) maxId = tripId;
    }
    return maxId + 1;

     

    추가로 5일차에는 Trip 관련 클래스에 아래 코드와 같이 싱글톤 패턴을 적용함.

    private TripJsonManager() {}
    
    private static class SingletonHelper {
        private static final TripJsonManager INSTANCE = new TripJsonManager();
    }
    
    public static TripJsonManager getInstance() {
        return SingletonHelper.INSTANCE;
    }

    ⭐어려웠던 점


    1. 프로젝트 구조 설정

    스프링을 제대로 다루어본 팀원이 한 분밖에 없었음. 그래서 처음에는 과제 내용을 이해하고, 프로젝트 구조를 설계 및 역할 분배를 하면서 시간을 보냈음. MVC 패턴으로 구조를 설정하기 위해서 비슷한 프로젝트들을 찾아보면서 구조를 참고하고자 아침부터 계속 회의를 진행했음. 결론적으로는 한 명이 화면 공유를 하여 같이 패키지 구성을 완료한 후에 푸시하는 방법을 사용함.

    2. IntelliJ에서 Git 명령어 사용

    인텔리제이에서 Git 관련 작업을 진행할 때, 터미널에서 git 명령어를 사용하면 수정된 파일들이 제대로 업로드되지 않는 문제가 있었음. 팀원 전체가 동일한 문제를 겪었음. 이 문제의 해결책으로 터미널 대신 인텔리제이의 GUI를 사용하여 커밋하면, 파일이 정상적으로 Git 리포지토리에 업로드되는 것을 확인함.

    3. tripId.json에서 itineraries 키가 사라지는 현상

    [여행 기록하기]를 실행하고 생성된 해당 tripId.json 파일을 보면 itineraries라는 키가 존재함.

    // 생성된 1.json
    {
      "trip_id": 1,
      "itineraries": []
    }

     

    그 다음에 [여행 수정하기]로 해당 여행의 이름을 수정하면 itineraries 키가 없어지고 아래 코드와 같아짐. 이후 해당 tripId를 CRUD 하려고 하면 못찾는 문제가 발생함.

    // 수정 후 1.json
    {
      "end_date": "2024-04-05",
      "trip_id": 1,
      "trip_name": "test",
      "start_date": "2024-04-01"
    }

     

    updateTripIdFile() 메소드에 TODO로 itineraries에 대한 추가 구현이 필요하다고 적어놓았는데, 여정 관리를 담당하는 팀원과의 소통 오류와 TripTable.json과 착각해서 실수를 한 문제였음.

    // 생성된 TripTable.json
    {
      "trips": [
        {
          "end_date": "2024-04-05",
          "trip_id": 1,
          "trip_name": "test",
          "start_date": "2024-04-01"
        }
      ]
    }

     

    먼저, 문제가 발생하면 여정 관리를 담당한 팀원이 수정할 것이라고 생각했음. 그리고 여행 테이블을 생성하는 코드를 변형해서 여행 테이블 수정 코드를 만들었는데, 착각해서 TripId.json에도 똑같이 작동하도록 한 것이었음. end_date, trip_name, start_date 부분은 삭제하고 itineraries 키를 추가하여 잘 해결함.

    ▲ commit message 일부

    4. TripTable.json이 없을 때 생성되지 않는 현상

    trip_name 중복 검사 코드를 추가하지 전까지는 TripTavle.json이 resources 패키지에 없을 때 자동으로 초기화되어 생성되었음. 존재하지 않는 TripTable.json 파일을 읽으려고 해서 오류가 발생하는 것 같음. 

    List<Trip> existingTrips = readTripTable();

     

    이 문제를 해결하기 위해서 initializeTripTable() 메소드로 TripTable이.json을 조회하기 전에 초기화하도록 했음.

    /**
      * 모든 여행 데이터를 조회하여 리스트 반환
      * @return 저장된 모든 여행 정보가 담긴 리스트
      */
    public List<Trip> readTripTable() throws FileIOException {
    	initializeTripTable();
    	// 조회하여 리스트를 반환하는 로직
    }

    ⭐후기


    ▲ 토이 프로젝트 7팀 발표 자료

    • 팀원들과 도서관 관리 프로젝트를 미리 해봤었지만, 본격적으로 해보는 것은 처음이어서 어려웠음. 특히, json 파일을 관리하는 방법을 공부할 때 밤을 새우기도 하면서 어려움을 느낌.
    • 패키지 구성 및 MVC 패턴, 리팩토링에 대해서 잘 알지 못해 다양한 경험과 학습이 필요하다고 생각하게 됨.
    • 앞의 팀들과 다른 구조의 발표 내용에 대해 칭찬을 받음. 발표 자료를 만드느라 다른 팀의 발표를 제대로 집중해서 듣지 못한 것이 아쉬웠음. 그 중에서도 1팀이 MVC 패턴을 가장 깔끔하게 구현했다고 들었음. 어떤 구조인지 참고하여 다음 프로젝트에 적용하면 좋을 것 같음.
    • 처음 이 프로젝트를 시작했을 때, 내가 과연 이 모든 것을 해낼 수 있을까 하는 의구심을 가지고 있었음. 앞으로 더 많은 프로젝트가 나를 기다리고 있겠지만, 포기하지 않고 열심히 하겠음. 다음 프로젝트가 시작되기 전까지 스프링에 대해서 꼭 미리 학습할 것임.

    ▲ 1팀 발표 Zoom

     

    이 글은 패스트캠퍼스백엔드 개발 캠프에서 공부한 내용을 작성한 것입니다.
    Comments