코드 리펙토링 도전기
기존 프로젝트 속 코드는 중복되거나, 한 클래스에 너무 많은 책임이 있는 등 기능을 굴러가나 효율적이지 못한 코드로 이루어져 있었다. 프로젝트를 이어 나가기 전 리펙토링을 통해 한층 더 나은 설계를 해보고자 리펙토링을 시작하게 되었다.
How to start...?
일단 기본적으로 있어야 할 테스트코드가 없었기에 감을 잡기가 어려웠던 상황..!!
테스트코드를 먼저 적기에는 SRP원칙이 어긋난 부분이 많았기에 코드를 먼저 분리하는 것이 맞겠다는 결론이 나왔다!
SRP(단일 책임 원칙) 이란?
- 한 클래스는 오직 하나의 액터(사용자)만을 위한 책임을 가져야 한다.
- 각 소프트웨어 모듈이 변경해야 하는 단 하나의 이유를 가져야 한다.
Step1. 코드 분리하기
✔️ 단일 책임 원칙을 지키면 좋을 이유는 무엇일까?
1. 유지 보수가 쉬우며 이해하기가 쉽다.
2. 테스트와 재사용이 용이하며 디버깅이 쉬워진다.
3. 시스템이 커지더라도 독립적으로 작동하기 때문에 서로에게 영향을 주지 않는다.
1️⃣ 현재 코드에서의 책임 분석
public ChatMessageDetailResponse sendMessage(Long chatRoomId, String message, Long userPk) {
ChatRoom chatRoom =chatRoomRepository
.findById(chatRoomId)
.orElseThrow(() -> ChatRoomNotFoundException.EXCEPTION);
chatRoom.updateChatTime(); // 채팅 입력 시간에 따른 채팅방 ch_update_at 업데이트
User user = userRepository.findById(userPk).orElseThrow(() -> UserNotFoundException.EXCEPTION);
Chatting chatMessage =Chatting.builder().chatRoom(chatRoom).sender(user).content(message).build();
chattingRepository.save(chatMessage);
ChatMessageDetailResponse detailResponse = new ChatMessageDetailResponse(user.getUid(), message, MessageType.TEXT);
return detailResponse;
}
한눈에 봐도...많다!
해당 메서드의 책임을 분석해보면
1. 채팅방 존재 여부 검증과 시간 갱신
2. 사용자 존재 여부 검증
3. 채팅 메시지 저장
4. 응답 객체 생성
이렇게 나누어 볼 수 있다.
그렇다면 어떻게 이 책임을 분리할 수 있을까?
2️⃣ 책임 분리하기
private final ChatRoomService chatRoomService;
private final UserService userService;
private final ChattingRepository chattingRepository;
private final ChatMessageMapper chatMessageMapper;
public ChatMessageDetailResponse sendMessage(Long chatRoomId, String message, Long userPk) {
ChatRoom chatRoom = chatRoomService.findAndUpdate(chatRoomId);
User user = userService.findUser(userPk);
Chatting chatMessage = saveMessage(chatRoom, user, message);
return buildChatMessageDetailResponse(user, message);
}
// ChatRoomService
public ChatRoom findAndUpdateChatRoom(Long chatRoomId) {
ChatRoom chatRoom = chatRoomRepository
.findById(chatRoomId)
.orElseThrow(() -> ChatRoomNotFoundException.EXCEPTION);
chatRoom.updateChatTime();
return chatRoom;
}
// UserService
public User findUser(Long userPk) {
return userRepository.findById(userPk)
.orElseThrow(() -> UserNotFoundException.EXCEPTION);
}
// ChattingService
public Chatting saveMessage(ChatRoom chatRoom, User user, String message) {
Chatting chatMessage = Chatting.builder()
.chatRoom(chatRoom)
.sender(user)
.content(message)
.build();
return chattingRepository.save(chatMessage);
}
// ChattingService
public ChatMessageDetailResponse buildMessageDetailResponse(User user, String message) {
return new ChatMessageDetailResponse(user.getUid(), message, MessageType.TEXT);
}
다른 코드 역시 위와 같은 방향으로 SRP원칙을 지켜준다! 이제 다음 Step은..!!!!
- to be continued -
*참고*
Spring MSA 프로젝트에서 단일 책임 원칙을 지키기 위한 리팩토링
Spring MSA 프로젝트에서 단일 책임 원칙을 지키기 위한 리팩토링 우리팀은 MSA프로젝트에서 분산추적을 위해 Zipkin을 적용했다. 여기서 서버간 추적을 공유하기 위해서는 TraceId를 공유해야 한다는
curiousjinan.tistory.com
단일 책임 원칙(SRP) - 한 클래스는 오직 하나의 액터만을 위한 책임을 가져야 한다.
안녕하세요! 개발자 stark입니다. 이번 포스팅은 SOLID 원칙 중 첫 번째인 단일 책임 원칙(Single Responsibility Principle, SRP)에 대한 내용입니다. 굉장히 흔한 지식이지만 로버트 마틴이 작성한 SRP 관련
curiousjinan.tistory.com
'프로젝트' 카테고리의 다른 글
구글 로그인 아키텍처 설계 (Spring Boot + MongoDB) (0) | 2025.05.11 |
---|---|
[회고] 프로젝트 회고 <너쫌친당> (0) | 2025.02.17 |
웹소켓 연결, 끊김 감지 (feat. 채팅 목록 unreadCount 구현) (0) | 2025.01.31 |
웹소켓 STOMP로 채팅구현하기 (with Spring) +웹소켓 테스트 사이트 추천 (0) | 2024.11.17 |
[데이터베이스 설계] Null을 피해야 하는 이유? (4) | 2024.10.13 |