[SB 3기] 코드잇 스프린트 미션 1, 2 회고

JHLee·2025년 5월 20일

📖 미션 내용

🚀 스프린트 미션 1

  • 채팅 서비스의 도메인 모델 설계 및 구현
  • 서비스 인터페이스 설계 및 구현
    - 도메인 모델 별 CRUD
    • Java Collections Framework 기반
  • 의존성 주입
  • Git, GitHub를 통한 프로젝트 관리

🚀 스프린트 미션 2

  • File IO를 통한 데이터 영속화
  • 레포지토리 설계 및 구현
  • 관심사 분리를 통한 레이어 간 의존성 주입

💡 코드 리뷰 사항 및 개선 포인트

📌 스프린트 미션1

1. 타입 구분의 필요성: Primitive vs Wrapper

long(primitive)과 Long(wrapper)의 차이를 구분하게 되었고, 각각 어떤 경우에 사용해야 하는지 알게 되었다. (primitive - 기본형, wrapper - 컬렉션 사용, null 허용 등)
autoboxing/unboxing에 따른 불필요한 형변환도 코드를 작성하는 데에 고려하면 좋다는 것을 알 수 있었다.

단, 해당 필드 타입은 요구사항에 타입이 명시되어 있었기에 수정하지 않았다.

2. 네이밍 컨벤션

메서드명 setUpdatedAt()updateTimestamp()처럼 setter 메서드로 오해할 수 있는 네이밍을 수정했고, 클래스명은 channelMenu -> ChannelMenu처럼 카멜케이스로 통일했다.
오해의 여지가 있는 네이밍이 협업에 큰 영향을 미칠 수 있다는 것을 알게 되었다.

3. 구현체 대신 인터페이스 타입 활용

JCFChannelService를 직접 사용하는 것보다는 ChannelService 인터페이스를 통해 객체를 다루도록 수정했다. 이로써 다형성이 적용되고, 코드의 유연성/확장성에 긍정적인 영향을 주었다.

4. 데이터 타입 선택시 고려 필요

채널 리스트를 List 타입으로 구현하였는데, 이는 데이터 양이 엄청나게 많아질 경우 비효율적일 수 있어 Map<UUID, Channel> 타입으로 수정하였다.
데이터 타입은 시간복잡도를 고려하여 선택해야 하는 것을 알게 되었다.

5. AutoCloseable 구현체는 try-with-resources로 관리

ScannerAutoCloseable 구현체이므로, try-with-resources문을 활용하는 것이 자원 관리를 깔끔하게 할 수 있다. 이는 close()가 호출되지 않는 상황에 생기는 리소스 누수를 방지할 수 있다.

➕ 추가사항

  • try-catch를 통한 예외 처리시, catch 부분에 무언가 로직을 추가하고 싶어지는 유혹을 조심하고, 예외를 핸들링하는 목적에만 집중하기

📌 스프린트 미션 2

1. serialVersionUID는 클래스마다 고유한 값으로 설정

serialVersionUID은 각 클래스별 다른 값으로 설정해주어야 한다.

2. 도메인은 최대한 퓨어한 상태로 설계

각 도메인은 자신의 역할과 데이터에만 집중하도록 설계하는 것이 좋다.
설계시, '더 근본적인 도메인을 기준으로 설계한다'를 고려하여 의존성을 따져보는 게 좋다.
ChannelMessage, User리스트를 직접 가지고 있는 구조는 의존성이 복잡해지고 도메인 간 결합도가 높아진다.

    private List<Message> messageList;      // 채널에 등록된 메시지 리스트
    private List<User> joinUserList;        // 채널에 참여중인 유저리스트

예를 들어 MessageChannel이 있어야만 존재할 수 있으므로, MessageChannelId를 가지고 있는게 더 자연스럽다.

  • DDD(Domain Driven Design) 개념 중, 도메인 분리 개념 참고

3. 네이밍 컨벤션

레포지토리의 메서드 명 중 read() -> get() 또는 find() 로 바꾸는게 의미를 더 명확히 전달할 수 있다.
또한 ~From은 인스턴스를 생성할때 주로 사용되므로, 조회 조건을 나타내는 경우에는 ~By를 사용하는 것이 더 적절하다.

4. 도메인간 의존 방향을 고려한 코드

ChannelUser를 의존하는 방향이라면, 코드를 다음과 같이 수정하는 것이 좋다.

// AS IS
if (targetUser.getJoinChannelList().contains(ch)) {

// TO BE
if (channelService.findChannelsByUserId(UUID id).contains(ch)) {

도메인의 의존 방향을 잘못 설계하면 이후 코드 전체에 영향을 미쳐 큰 리펙토링이 필요해질 수 있다.
따라서 도메인 설계시 의존성 방향을 충분히 고민해야 한다.

5. 파라미터는 객체 식별자만 넘기는 방향

leaveChannel(User user, Channel channel)leaveChannel(UUID userId, UUID channelId) 로 수정하였다.
서비스 메서드의 파라미터로는 객체 전체가 아닌, 식별자만 넘기는 것이 더 적절하다는 점을 배웠다.

➕ 추가사항

  • 비지니스 로직과 의존성이 많은 구성을 분리하는 방향을 생각해보기 (예를 들어, 의존성이 많이 엮여있는 로직을 따로 모아 ChatService 등과 같은 서비스로 분리)
  • 도메인 설계시, 각 엔티티들간의 관계에 집중해서 설계하기

📝 회고

👍 좋았던 점

이번 미션을 통해, 초반 도메인 설계의 중요성을 깨달았다.
특히, 각 도메인간의 의존성을 생각하며 설계하는 것이 중요하고 설계가 잘못된 경우 수정하는 데에 많은 시간이 소요되므로, 초반 설계에 충분한 시간을 들이는 것이 이후 개발 효율성에 중요하다는 것을 알게 되었다.

😅 아쉬웠던 점

  • 초기 설계 시 도메인 간의 관계를 충분히 고민하지 못해, 리뷰 이후에 수정하게 된 부분들이 많았다.
    또한 메서드 네이밍이나 데이터 타입 선택과 같은 부분들을 신중히 고민해보지 않은 점이 아쉬웠다.
  • 테스트를 Scanner를 통해 사용자의 입력을 받아 수행하게 구현하였는데, 테스트가 오히려 복잡해졌고, 매번 데이터를 새로 입력해야 하는게 번거로웠다.
    아직 Junit을 활용한 테스트를 배우지 않았기에, 각 로직을 테스트 할 수 있는 테스트 메서드를 만들어 메시지를 출력하는 방식이 더 효율적이었을 것 같다.

🧠 배운 점

  • 도메인 설계 시 "누가 누구를 의존해야 하는가?"에 대한 고민을 충분히 해야 한다.
  • Java의 다형성 특징을 이해하고 인터페이스 기반 설계를 활용해야 한다.
  • 네이밍이 코드의 가독성과 협업 효율성에 큰 영향을 미친다. (⭐️ 이름을 잘 짓는건 너무나 중요함)
  • 코드의 디테일한 부분들도 신경써야 추후 변경해야 할 부분이 적어진다.
profile
개발자로 성장하기

0개의 댓글