feat: CSV 파싱 및 대화 통계 집계 구현#6
Conversation
|
| public MessageType classify(String content) { | ||
| String text = content.strip(); | ||
|
|
||
| if (text.equals(EMOTICON_MARKER)) { |
There was a problem hiding this comment.
왜 이런 체크를 하는지 private boolean 함수를 만들면 어떨까요?
함수명에 명시해서요
| private static final String EMOTICON_MARKER = "이모티콘"; | ||
| private static final Pattern PHOTO = Pattern.compile("사진( \\d+장)?"); | ||
|
|
||
| public MessageType classify(String content) { |
There was a problem hiding this comment.
근데 이거 MessageType에 있는게 더 응집력이 있지 않을까요?
| private Reader stripBom(Reader in) throws IOException { | ||
| PushbackReader pushback = new PushbackReader(in, 1); | ||
| int first = pushback.read(); | ||
| if (first != -1 && first != BOM) { |
There was a problem hiding this comment.
이건 꼭 private 함수로 빼서 왜 이런 체크를 하는지 명시하면 좋을것 같아요
| try { | ||
| String speakerName = csvRow.get("User"); | ||
| String text = csvRow.get("Message"); | ||
| LocalDateTime sentAt = parseSentAt(csvRow.get("Date")); |
There was a problem hiding this comment.
User, Message, Date 컬럼이 없으면 fail fast로 에러를 반환하는건 어떨까요?
| Objects.requireNonNull(ownerName, "ownerName"); | ||
| Objects.requireNonNull(partnerName, "partnerName"); | ||
| if (ownerName.equals(partnerName)) { | ||
| throw new IllegalArgumentException("OWNER와 PARTNER는 서로 달라야 합니다."); |
There was a problem hiding this comment.
우리 exception handler 에 등록된 exception으로 전환하면 어떨까요?
| } | ||
| } | ||
|
|
||
| public SpeakerRole roleOf(String speakerName) { |
There was a problem hiding this comment.
이 함수도 SpeakerRole 안으로 들어가는게 더 응집력이 있을거 같아요
| MessagePeriodAccumulator period = new MessagePeriodAccumulator(); | ||
| Set<LocalDate> activeDays = new HashSet<>(); | ||
|
|
||
| for (RawMessage message : messages) { |
There was a problem hiding this comment.
이 for문에서 너무 많은 일이 일어나요 private으로 분리하는게 필요해보입니다
| continue; // 소수 화자는 모든 통계에서 제외 | ||
| } | ||
|
|
||
| switch (role) { |
There was a problem hiding this comment.
이 기능도 SpeakerRole 안으로 들어가면 더 응집력 있는 코드가 될 것 같아요
There was a problem hiding this comment.
private boolean isNotOneToOneChatRoom()| } | ||
|
|
||
| MessageType type = classifier.classify(message.text()); | ||
| switch (type) { |
| long partnerCount = 0; | ||
| long textCount = 0; | ||
| long emoticonCount = 0; | ||
| long photoCount = 0; |
There was a problem hiding this comment.
이렇게 따로 두는것 보다 객체를 만들어서 관리하면 더 좋을것 같아요
각각의 숫자가 어떻게 연관 있는지 흐름을 파악하는게 어려워요
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| final class MessagePeriodAccumulator { |
There was a problem hiding this comment.
이름은 Accumulator 인데 하는 일은 날짜를 관리(validate)하는것 같아 보여요
| period.accumulate(message.sentAt()); | ||
| } | ||
|
|
||
| List<SpeakerCount> speakerCounts = messageCountBySpeaker.entrySet().stream() |
There was a problem hiding this comment.
new SpeakerCount(entry);로 변경하면 stream을 사용하는데 더 적합할것 같아요
| .map(entry -> new SpeakerCount(entry.getKey(), entry.getValue())) | ||
| .toList(); | ||
|
|
||
| return new PreScanSummary(speakerCounts, period.startedAt(), period.endedAt(), messages.size()); |
There was a problem hiding this comment.
new PreScanSummary(speakerCounts, period, messages);가 더 객체지향적으로 보여요
| .mapToLong(SpeakerCount::messageCount) | ||
| .min() | ||
| .orElse(0); | ||
| if (minCount < thresholds.minPerSpeakerMessages()) { |



요약
카카오톡 Mac CSV 파일을 읽어 대화 통계를 만드는 파싱 파이프라인을 구현했습니다.
CSV 파싱 → 1차 스캔 → 검증 → 2차 스캔
구현 내용
CSV 파싱 (CsvMessageParser)
1차 스캔 (PreScanner)
검증 (PreScanValidator)
2차 스캔 (ChatStatsAnalyzer)
테스트