[Refectoring] Sse로직을 재사용을 해보자 (Static, 메소드 오버로딩(overloading))
국비를 통해 처음 프로그래밍을 배우면서 팀프로젝트 진행하였습니다. 프로젝트의 기능은 잘 구현해서 해커톤 우수상을 받았지만, 코드는 당연히(?) 엉망이였습니다. 그리고 몇개월이 지난 지
sol-b.tistory.com
이전 글에서 이어지는 Sse 실시간 알림 기능을 리펙토링하는 글입니다.
이전에는 Static으로 Sse기능을 Static영역에서 공통으로 관리하여 사용했습니다.

이후 Sse기능을 Strategy pattern으로 리펙토링하였습니다.
그 이유는 각 서비스마다 Sse를 사용하여 알림을 보내는것을 전략으로 생각한다면
Strategy Pattern으로 적용하면 되지 않을까? 라는 생각에서부터 시작되었습니다.
refector : SSE static -> Strategy Pattern by ReadnThink · Pull Request #2 · ReadnThink/pocoapoco-refectoring
기능 구현 Static으로 SSE 알림기능을 사용하던것을 Strategy Pattern으로 변경하여 변화에 유연한 코드로 변경 주목 포인트 SseSender클래스를 삭제하고 각 알림기능의 구현체를 추가하였습니다. @Configur
github.com
하지만 결과적으로 Strategy Pattern은 적절하지 않다고 결론을 내렸습니다.
그 이유는 글, 댓글, 좋아요, 리뷰 등 알림이 있을때마다 Sse를 사용하게 되는데
실제로 Sse가 사용될때 특별히 알고리즘 전략같이 많은것이 바뀌는게 아니라,
매개변수들만 조금씩 변하는 형태이기 때문입니다.
조금 더 객체지향적으로 그리고 스프링이 권장하는 Ioc컨테이너를 이용하여 Bean으로 관리하는게
더 좋겠다고 생각했습니다.
그리고 기존에 하드코딩하였던 메세지 내용과 sse의 name을 Enum으로 관리하였습니다.
파라미터의 경우 너무 길다고 판단하여 UserSseKey와 SseAlarmData를 만들어 관리하였습니다.
하드코딩한 내용을 Enum으로 변경하고
메서드의 인자를 공통화시켜 가독성을 높이고 유지보수가 유연하게 가능해졌습니다!

우선 Enum과 인자로 넘길 DTO입니다.
@AllArgsConstructor
@Getter
public enum AlarmMessagesEnum {
CHECK_REVIEW("리뷰가 등록되었어요! 확인해 보세요!"),
ADD_COMMENT_TO_ACTIVITY("\"모임에 댓글을 남겼습니다."),
ADD_COMMENT_TO_COMMENT("\" 댓글에 댓글을 남겼습니다."),
ADD_REVIEW_TO_CREWS("모임이 종료되었습니다! 같이 고생한 크루들에게 후기를 남겨보세요!"),
FOLLOW("님이 회원님을 팔로우 합니다💕"),
LIKE("\" 모임에 좋아요를 눌렀습니다💕")
;
private final String value;
}
@AllArgsConstructor
@Getter
public enum AlarmTypeEnum {
ALARM("alarm");
private final String value;
}
@Getter
public class SseAlarmData {
private final String fromUser;
private final String targetUser;
private final AlarmMessagesEnum message;
@Builder
public SseAlarmData(final String fromUser, final String targetUser, final AlarmMessagesEnum message) {
this.fromUser = fromUser;
this.targetUser = targetUser;
this.message = message;
}
}
@Getter
public class UserSseKey {
private final String userSseKey;
@Builder
public UserSseKey(final String userSseKey) {
this.userSseKey = userSseKey;
}
}
SseSender입니다.
@Component
public class SseSender {
public void sendAlarmToTargetUser(final UserSseKey userSseKey, final SseAlarmData data) {
SseEmitter userSseEmitter = getUserEmitter(userSseKey.getUserSseKey());
try {
userSseEmitter
.send(SseEmitter
.event()
.name(ALARM.getValue())
.data(data.getMessage().getValue()));
} catch (Exception e) {
sseEmitters.remove(userSseKey);
}
}
private static SseEmitter getUserEmitter(final String userSseKey) {
return sseEmitters.get(userSseKey);
}
}
SseSender를 사용하는 Service 코드입니다.
~~
sendSseAlarm(followingUser, user);
~~
}
private void sendSseAlarm(final User followingUser, final User user) {
sseSender.sendAlarmToTargetUser(
UserSseKey.builder()
.userSseKey(user.getUsername())
.build(),
SseAlarmData.builder()
.targetUser(followingUser.getNickName())
.message(FOLLOW)
.build()
);
}
느낀점
Sse기능을 리펙토링하는데 많은 고민을 하였습니다.
어떻게 변경해야 유지보수가 더 편해질지, 다른사람에게 더 가독성이 있을지, 효율성이 괜찮은 방법인지 등
다양한 고민을 해보았습니다.
지금 실력에서 최선을 다했지만, 앞으로 더 변경될 부분이 충분히 많이 있다고 생각됩니다.
그런 의미에서 코드의 질은 관심이라는 생각이 들었습니다.
관심은 곧 리펙토링이되고 리펙토링을 자주하는 개발자는 실력이 늘 수 밖에 없다고 느꼈습니다.
앞으로도 내가 작성한 코드, 다른사람이 작성한 코드를 더 깊이 들여다 보고 리펙토링할 곳은 없을까?
라는 고민을 지속적으로 하는 개발자가 되야겠다고 느꼈습니다!
'Project > 팀프로젝트 - 운동메이트' 카테고리의 다른 글
Sse를 활용해 실시간 알림기능 어떤기술을 사용해야할까? (0) | 2023.09.19 |
---|---|
[Refectoring] Sse로직을 재사용을 해보자 (Static, 메소드 오버로딩(overloading)) (0) | 2023.09.09 |
[Refectoring] Sse로직을 재사용을 해보자 (Static, 메소드 오버로딩(overloading))
국비를 통해 처음 프로그래밍을 배우면서 팀프로젝트 진행하였습니다. 프로젝트의 기능은 잘 구현해서 해커톤 우수상을 받았지만, 코드는 당연히(?) 엉망이였습니다. 그리고 몇개월이 지난 지
sol-b.tistory.com
이전 글에서 이어지는 Sse 실시간 알림 기능을 리펙토링하는 글입니다.
이전에는 Static으로 Sse기능을 Static영역에서 공통으로 관리하여 사용했습니다.

이후 Sse기능을 Strategy pattern으로 리펙토링하였습니다.
그 이유는 각 서비스마다 Sse를 사용하여 알림을 보내는것을 전략으로 생각한다면
Strategy Pattern으로 적용하면 되지 않을까? 라는 생각에서부터 시작되었습니다.
refector : SSE static -> Strategy Pattern by ReadnThink · Pull Request #2 · ReadnThink/pocoapoco-refectoring
기능 구현 Static으로 SSE 알림기능을 사용하던것을 Strategy Pattern으로 변경하여 변화에 유연한 코드로 변경 주목 포인트 SseSender클래스를 삭제하고 각 알림기능의 구현체를 추가하였습니다. @Configur
github.com
하지만 결과적으로 Strategy Pattern은 적절하지 않다고 결론을 내렸습니다.
그 이유는 글, 댓글, 좋아요, 리뷰 등 알림이 있을때마다 Sse를 사용하게 되는데
실제로 Sse가 사용될때 특별히 알고리즘 전략같이 많은것이 바뀌는게 아니라,
매개변수들만 조금씩 변하는 형태이기 때문입니다.
조금 더 객체지향적으로 그리고 스프링이 권장하는 Ioc컨테이너를 이용하여 Bean으로 관리하는게
더 좋겠다고 생각했습니다.
그리고 기존에 하드코딩하였던 메세지 내용과 sse의 name을 Enum으로 관리하였습니다.
파라미터의 경우 너무 길다고 판단하여 UserSseKey와 SseAlarmData를 만들어 관리하였습니다.
하드코딩한 내용을 Enum으로 변경하고
메서드의 인자를 공통화시켜 가독성을 높이고 유지보수가 유연하게 가능해졌습니다!

우선 Enum과 인자로 넘길 DTO입니다.
@AllArgsConstructor
@Getter
public enum AlarmMessagesEnum {
CHECK_REVIEW("리뷰가 등록되었어요! 확인해 보세요!"),
ADD_COMMENT_TO_ACTIVITY("\"모임에 댓글을 남겼습니다."),
ADD_COMMENT_TO_COMMENT("\" 댓글에 댓글을 남겼습니다."),
ADD_REVIEW_TO_CREWS("모임이 종료되었습니다! 같이 고생한 크루들에게 후기를 남겨보세요!"),
FOLLOW("님이 회원님을 팔로우 합니다💕"),
LIKE("\" 모임에 좋아요를 눌렀습니다💕")
;
private final String value;
}
@AllArgsConstructor
@Getter
public enum AlarmTypeEnum {
ALARM("alarm");
private final String value;
}
@Getter
public class SseAlarmData {
private final String fromUser;
private final String targetUser;
private final AlarmMessagesEnum message;
@Builder
public SseAlarmData(final String fromUser, final String targetUser, final AlarmMessagesEnum message) {
this.fromUser = fromUser;
this.targetUser = targetUser;
this.message = message;
}
}
@Getter
public class UserSseKey {
private final String userSseKey;
@Builder
public UserSseKey(final String userSseKey) {
this.userSseKey = userSseKey;
}
}
SseSender입니다.
@Component
public class SseSender {
public void sendAlarmToTargetUser(final UserSseKey userSseKey, final SseAlarmData data) {
SseEmitter userSseEmitter = getUserEmitter(userSseKey.getUserSseKey());
try {
userSseEmitter
.send(SseEmitter
.event()
.name(ALARM.getValue())
.data(data.getMessage().getValue()));
} catch (Exception e) {
sseEmitters.remove(userSseKey);
}
}
private static SseEmitter getUserEmitter(final String userSseKey) {
return sseEmitters.get(userSseKey);
}
}
SseSender를 사용하는 Service 코드입니다.
~~
sendSseAlarm(followingUser, user);
~~
}
private void sendSseAlarm(final User followingUser, final User user) {
sseSender.sendAlarmToTargetUser(
UserSseKey.builder()
.userSseKey(user.getUsername())
.build(),
SseAlarmData.builder()
.targetUser(followingUser.getNickName())
.message(FOLLOW)
.build()
);
}
느낀점
Sse기능을 리펙토링하는데 많은 고민을 하였습니다.
어떻게 변경해야 유지보수가 더 편해질지, 다른사람에게 더 가독성이 있을지, 효율성이 괜찮은 방법인지 등
다양한 고민을 해보았습니다.
지금 실력에서 최선을 다했지만, 앞으로 더 변경될 부분이 충분히 많이 있다고 생각됩니다.
그런 의미에서 코드의 질은 관심이라는 생각이 들었습니다.
관심은 곧 리펙토링이되고 리펙토링을 자주하는 개발자는 실력이 늘 수 밖에 없다고 느꼈습니다.
앞으로도 내가 작성한 코드, 다른사람이 작성한 코드를 더 깊이 들여다 보고 리펙토링할 곳은 없을까?
라는 고민을 지속적으로 하는 개발자가 되야겠다고 느꼈습니다!
'Project > 팀프로젝트 - 운동메이트' 카테고리의 다른 글
Sse를 활용해 실시간 알림기능 어떤기술을 사용해야할까? (0) | 2023.09.19 |
---|---|
[Refectoring] Sse로직을 재사용을 해보자 (Static, 메소드 오버로딩(overloading)) (0) | 2023.09.09 |