Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[와인잔 5조] 1차 세미나 과제 #2

Closed
3 tasks done
choyeongju opened this issue Oct 8, 2024 · 2 comments
Closed
3 tasks done

[와인잔 5조] 1차 세미나 과제 #2

choyeongju opened this issue Oct 8, 2024 · 2 comments

Comments

@choyeongju
Copy link
Member

choyeongju commented Oct 8, 2024

⭐️ 역할 분배

일단 모두가 각자 구현 할 수 있는데까지 모든 항목을 최대한 구현해오는 것을 목표로 했습니다! 오죠오죠 짱

기능 영주 의진 예은 효준 윤혁
일기 글자수 30자로 제한 완료 완료 완료 완료 완료
일기 삭제 기능 추가 ⭐️ 완료 완료 완료 완료 완료
일기 수정 기능 추가 ⭐️ 완료 완료 완료 완료 완료
삭제된 일기 복구 기능 추가 ⭐️⭐️ 완료 완료 완료 완료 완료
일기 수정 일일 2회 제한 기능 추가 ⭐️⭐️ 완료 고민중 고민중 완료 완료
Application 종료 시에도 일기 저장 목록 유지되는 기능 추가 ⭐️⭐️⭐️ 고민중 완료 고민중 완료 완료
이모지 등을 1글자로 계산하는 기능 추가 ⭐️⭐️⭐️⭐️⭐️ 완료 완료 고민중 완료 완료

⭐️ 코드 토크

영주

구현 과정

  • delete
    • 클라이언트에게서 받은 String을 어디서 변환 처리할 것인지에 대한 고민을 했다.
    • 서비스 계층은 비즈니스 로직을 담는 곳이므로, 서비스 계층에서 형 변환 처리를 해주었다.
  • patch
    • 데이터의 유효성 검증 과정을 어디에서 처리할 것인지에 대한 고민을 했다.
    • 트랜잭션의 실행 단위를 고민해 보았을 때, 서비스 계층에서 예외를 던지게끔 하였다.
    • 검증 과정(Validator)을 서비스 계층에다 했는데, 스프링에서 @Valid 어노테이션은 컨트롤러 계층에서 쓰는 것을 고려해 보았을 때.. 컨트롤러 계층에서 Validator 클래스의 메서드 호출해서 검증한 다음 서비스 계층으로 넘겨주는 형식으로 코드를 리팩토링 하는 것이 좋을 것 같단 생각이 들었다.
  • 삭제된 일기를 복구하는 기능
    • 선택 과제 구현을 시작할 때, Map<Long, Diary> 형태로 저장소를 구현하고 Diary 객체에 속성 필드값을 추가하는 방법을 고려했으나, 코드에 변경이 너무 많이 일어날 것 같아서 다른 방식을 채택했다.
    • ’삭제된 일기’를 저장해두는 별도의 자료구조를 만들었다.
  • 일기 수정은 하루에 2번만
    • 복구 기능과 마찬가지로 ’수정 횟수’와 ‘마지막 수정 날짜’ 를 저장해두는 별도의 자료구조를 만들었다.
  • application 종료 후에도 일기가 계속해서 저장되도록
    • 일기의 Id를 몇 번까지 사용했지에 대한 정보를 어떻게 계속하여 가지고 있을 것인지에 대해 고민
  • 이모지 처리
    • 정규식을 사용해서 처리하였다.
    • But, 이렇게 처리하면 너무 간단해서 팟짱님의 다른 의도가 있지 않았을까? 라는 생각이 든다..!

포럼 진행 후 소감

  • 내가 파일 입출력 부분을 구현할 때, 어디까지 아이디를 썼는지에 대한 정보(numbering)를 가지고 있는가? 에 대해서 고민해봐야겠다.

PR 링크

AND-SOPT-SERVER/yeongju.cho#2
AND-SOPT-SERVER/yeongju.cho#4


의진

구현 과정

  • delete
    • HashMap의 remove()메소드를 사용하여 구현
  • patch
    • HashMap의 replace()메소드를 사용하여 구현
  • 삭제된 일기를 복구하는 기능
    • ’특정 일기만 복구 vs 모든 일기 복구’ 중 기능 명세에 대한 세부사항이 없어서 우선 restoreAll()이라는 메소드를 통해 모든 일기를 복구하도록 구현.
    • 삭제될 일기를 저장할 공간 생성 후 삭제되는 경우 아이디와 내용을 유지한 채로 저장(복구 시 아이디 유지를 위함)
  • 일기 수정은 하루에 2번만
    • ’하나의 일기 당 하루 2번 수정’이 아닌 ‘유저 당 하루 2번 수정’
    • 수정 날짜 및 횟수를 기록하는 공간 마련. 수정 시 마다 수정 날짜와 횟수 비교.
  • application 종료 후에도 일기가 계속해서 저장되도록
    • 종료 시 유지되는 방법으로 파일 입출력 선택
  • 이모지 처리
    • 길이가 제각각인 이모지 처리를 위한 Grapheme Cluster 적용

포럼 진행 후 소감

  • 딱 기능명세에만 집중했는데.. 주어진 것 뿐만 아니라 사용자 입장을 고려하는 등의 전체적인 흐름을 더 고민해야겠다는 생각이 들었다.

PR 링크

AND-SOPT-SERVER/uijin.kim#4
AND-SOPT-SERVER/uijin.kim#5


예은

구현 과정

  • patch
    • ConcurrentHashMap의 동일한 키와 값을 이용하여 기존의 body를 newBody로 바꾸는 작업을 통해 구현
  • delete
    • storage.remove 작업을 통해 해당 내용을 삭제하는 방식으로 구현했습니다.
  • 삭제된 일기를 복구하는 기능
    • 삭제된 일기를 복구하기 위해 삭제되는 일기를 보관하기 위한 deletedDiaries 를 만들었고 <Long, String> 을 키와 값으로 사용.
  • 일기 수정은 하루에 2번만
    • 일기 수정을 한 사람이 하루에 2번 할 수 있는가 ? vs 각각의 일기 당 2번씩 수정 가능한가를 두고 고민이 있었는데 후자에 대해 구현을 진행했습니다.
    • 각 일기가 수정시간과 수정횟수를 필드로 가지고, 유저가 일기를 수정할 경우 이를 증가시키는 방식입니다.
  • application 종료 후에도 일기가 계속해서 저장되도록
    • 파일 시스템을 이용하는 방식으로 구현
  • 이모지 처리
    • grapheme cluster를 세는 메서드와 grapheme cluster에서 이모지를 세는 메서드 두개를 구현하고 합하는 방식으로 구현할 예정입니다.

포럼 진행 후 소감

  • 메서드 분리를 통해서 가독성 향상을 할 필요성이 있다고 느꼈고, 각 클래스별로 책임에 대해 고민할 수 있는 시간이 되었다.

PR 링크

AND-SOPT-SERVER/yeeun.kim#3
AND-SOPT-SERVER/yeeun.kim#4


효준

구현 과정

  • patch
    • patch 와 같은 경우에는 hashMap의 똑같은 키 값에 덮어씌울 수 있다는 특성을 활용하여 구현을 진행하였습니다.
  • delete
    • delete와 관련하여서 remove 를 활용하여 제거하는 작업을 진행하였습니다.
  • 삭제된 일기를 복구하는 기능
    • 고민 : 복구를 하기 위해선 다른 곳에다 저장해야하지 않을까? -> 해결 : 파일에 저장하는 방식, 그냥 애플리케이션 실행 동안 저장 시킬 List를 만들자!
  • 일기 수정은 하루에 2번만
    • 고민 : 어떻게 매번 확인할 수 있을까? 오늘에 대해서 -> 해결 : 매번 코드를 실행할 때마다 확인함으로써 날짜를 확인하는 절차를 거친다면 다음날로 넘어가는 순간에 이 수정 횟수를 바꾸면 될 거 같다!
  • application 종료 후에도 일기가 계속해서 저장되도록
    • 고민 : 어떤 방식으로 저장해야할까? 다른 요구사항에도 영향이 가지 않을까? -> 해결 : interface를 활용하여서 상황마다 대처하고 확장성이 있도록 basic, file Repository에 대해서 분리하여 file에 대한 친구 basic한 필수 과제에 대한 친구의 로직을 따로 생각하여 진행하자!
  • 이모지 처리
    • 고민 : 어떻게 다양한 경우의 이모지들에 대해서 다 고려하지? -> 해결 : graphem clusters라고 사람이 인식할 수 있는 것을 1글자로 처리할 수 있게 하는 Extended grapheme clusters 정규식을 제공했다 이를 활용해서 처리하니 쉽게 구분할 수 있었다.

포럼 진행 후 소감

  • 의존관계가 역류하지 않도록 다들 잘 만든 것 같다.

PR 링크

AND-SOPT-SERVER/hyojun.kim#2
AND-SOPT-SERVER/hyojun.kim#4


윤혁

구현 과정

  • patch
    • 입력 id에 대해, HashMap의 해당 key 값의 value를 덮어쓰기
  • delete
    • 입력 id에 대해, HashMap의 해당 key를 삭제
  • 삭제된 일기를 복구하는 기능
    • 휴지통 기능을 수행하는 파일을 생성 → 삭제 시, 해당 파일에 데이터를 key, value 형태로 기록
    • 휴지통의 복구하려는 데이터의 key, value를 기존 storage에 put 해주면 올바른 형상으로 복구 완료 (버킷 관련 내용에서 추가 설명)
  • 일기 수정은 하루에 2번만
    • 실제 프로젝트였다면? → DB에서 특정 사용자의 일일 수정 횟수를 Tracking 했을 것 같다.
    • 현재 과제에서는 “사용자” 단위의 데이터를 관리하지 않으므로, 단순히 현재 사용자의 수정 기록을 Tracking하는 파일을 생성
    • 사용자가 일기 수정을 시도할 시
      → 파일에 기록된 수정 날짜가 오늘 이전이라면 → 파일 내용 clear (하루가 지났으므로)
      → 파일에 기록된 수정 날짜가 오늘이라면 → 데이터의 개수 확인 → 2 이상이라면 return false (일일 수정 제한은 2회)
      → 위의 두 단계를 거친 후 update 진행 (update 시 파일에 현재 날짜 기록)
  • application 종료 후에도 일기가 계속해서 저장되도록
    • 일기의 내용을 저장하는 파일, 휴지통 기능을 수행하는 파일을 각각 생성
    • DiaryRepository의 생성자 부분에서 두 파일을 모두 load하여 Java의 Map 객체에 할당
    • 생성, 수정, 삭제 시 Map과 파일의 내용을 동기화
  • 이모지 처리
    • graphem clusters 기반의 정규식을 사용
    • Unicode 기반 문제 해결 방식으로 해당 과제를 수행하고 싶었는데, 이모지의 Unicode 형식이 다양하기에 일괄적으로 관리할 수 있는 방법을 찾을 수 없었다. 결과적으로 정보 조사를 통해 해당 과제 해결.

포럼 진행 후 소감

  • 기능 분리! 가 이 과제의 핵심인 것 같은데, 다들 잘 구현을 한 것 같다.

PR 링크

AND-SOPT-SERVER/yunhyuk.jeon#2
AND-SOPT-SERVER/yunhyuk.jeon#3



⭐️ 챌린지 과제

String 에 대해 고민해보세요.

  • StringBuilder 를 사용하면 어떤 이점이 있는거죠?
    • String, StringBuilder, StringBuffer
  • UTF 가 뭐에요?
    • 이모지, 한글은 몇 byte 인가요?
  • 대문자와 소문자 구분은 중요한가요? 어떻게 생각하세요?
    • 키워드 : mysql collation

String 에 대한 고민..

❓String

✅ 특징

  • JAVA의 기본 자료형에 속하지 않는 class 이다.

  • Immutable (불변성)
    : 한 번 생성한 문자열 객체는 수정할 수 없다! → thread-safe

    String str = "Hello" // (1)문자열 리터럴
    str += "world!" // (2)
    
    String str1 = new String("Hello"); // (1)new
    str1 += " world"; // (2)

    (2)번 연산 수행하면서 새롭게 (2)Hello World! 를 위한 메모리를 할당하고, (1)로 초기화한 str 객체는 GC의 대상이 된다. → 반복되면 성능에 안좋음..

✅ 메모리 할당 (1)문자열 리터럴 : String Constant Pool 사용

String str1 = "Hello";
String str2 = "Hello";
  1. 문자열 리터럴을 통해서 str1을 생성하면 String Constant Pool에 저장
  2. str2의 내용이 str1과 동일하므로, 새로 공간을 만들어 할당하지 않고 String Constant Pool 에서 str1과 같은 주소를 가리킨다.
  • 동일한 문자열 리터럴 사용 시, 새로운 메모리를 할당하지 않으므로 메모리 낭비가 덜하다.

  • == 연산자로 정확한 비교 가능(메모리 주소 비교)
    (But, 리터럴 방식이든 new 방식이든 상관없이, 문자열 비교는 항상 equals() 하는 것이 좋다.)

    System.out.println(str1 == str2);  // true

✅ 메모리 할당 (2)new 키워드 사용 : Heap 영역

String str3 = new String("Hello");
String str4 = new String("Hello");
  1. new 키워드로 생성할 때마다 heap 에 새로운 String 객체 생성
  2. String Constant Pool 에 “Hello” 가 이미 있더라도, 새로운 객체 생성
  • 메모리 낭비의 가능성이 있다
  • 서로 다른 객체이므로 == 연산자가 아니라 equals() 메소드로 객체의 내용을 비교해야 한다.

❓StringBuilder 와 StringBuffer

✅ 특징

  • String 연산에서 문제점을 해결하기 위해서 등장!
    → 문자열을 더할 때, 기존의 데이터에 저장하는 방식 사용하므로 메모리 낭비가 적고, 속도가 빠르다.
  • Mutable (가변)
  • StringBuilder와 StringBuffer 두 클래스의 큰 차이점은 Thread Safety & 성능

✅ StringBuilder

StringBuilder sb = new StringBuilder();

@Override
public StringBuilder append(String str) {
    super.append(str);
    return this;
}
  • StringBuffer 보다 더 빠름!

✅ StringBuffer

StringBuffer sb = new StringBuffer();

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}
  • Thread-Safe
  • lock을 걸고 푸는 오버헤드 때문에 속도가 느리므로 남발하면 안된다!

정리

  • 문자열 변경이 빈번하지 않다! → String
  • StringBuffer
    • 문자열 변경 빈번 && 멀티쓰레드 환경O
    • static 으로 선언된 문자열 변경 시
  • StringBuilder
    • 문자열 변경 빈번 && 멀티쓰레드 환경X
    • 메서드 내에서 지역 변수로 사용할 때

UTF

❓ 무엇인가?

  • 유니코드(Unicode) 를 인코딩하기 위한 표준
  • 각 문자를 특정한 이진 형식으로 변환하는 방법을 정의

*유니코드 : 각 문자를 고유한 숫자로 매핑한 것

❓종류

✅ UTF-8

  • 가변 길이 인코딩 방식 (문자에 따라 1-4byte. 영어는 1byte)
  • 메모리 효율적

✅ UTF-16

  • 대부분의 문자를 2byte로 처리함

✅ UTF-32

  • 고정 길이 인코딩 방식 (모든 문자를 4byte)
  • 메모리 비효율적 but, 간단함!

대소문자 구분에 대하여..

❓대소문자 구분은 중요할까?!

ㅇㅇ 대소문자 구분 여부는 데이터베이스의 정렬 규칙(Collation) 과 밀접한 연관이 있므므로 중요하다!

  • 대소문자 구분이 필요한 경우 : 제품코드, 비밀번호 등
  • 대소문자 구분 필요없는 경우 : 이름, 주소 검색 등

❓MySQL Collation

CHAR, VARCHAR, TEXT 과 같은 문자열 Datatype 에는 Character setCollation 이라는 속성이 있다.

✅ Character set

  • 각 문자가 컴퓨터에 저장될 때 어떠한 ‘코드’로 저장될지에 대한 규칙의 집합
  • 저장공간의 크기
    • latin1 (2바이트) , utf8 (가변3바이트) , utf8mb4 (가변4바이트)
  • 프로그램과 데이터베이스가 문자를 주고받을 때 charset만 설정하면 됨!

✅ Collation

  • 특정 Character set 에 의해 DB에 저장된 값들을 ‘비교, 검색’ 하거나 문자들을 서로 ‘정렬’ 등의 작업을 위해 비교할 때 사용하는 규칙의 집합
  • TEXT 데이터를 정렬(ORDER BY)할 떄 사용
  • 종류
    • **u**tf8_general_ci: 대소문자 구분을 하지 않는 Collation
    • utf8_bin: 대소문자 구분을 하는 Collation

💬 Emoji

원래는 전 세계 모든 언어가 21bit 에 저장되기 때문에, mysql 에서 utf8 을 3바이트 가변 자료형으로 설계했다.

→ 널리 사용되던 MYSQL / MariaDB 의 구축 환경은 charset-utf8 , collation-utf8_general_ci 였다.

⏩ 하지만….. Emoji 문자열은 모두 4 Byte !!

  1. 이모지와 같은 4Byte 문자열을 utf8 에 저장하니까 손실되는 문제 발생.
  2. 가변-4바이트 UTF-8 문자열 저장 가능게끔 하는 utf8mb4 라는 charset 추가!

(+) 기존 utf8 시스템을 utf8mb4 로 바꿔도 값의 손실은 없다.

@choyeongju choyeongju changed the title 와인잔조 5조 1주차 세미나 과제 와인잔조 5조 1차 세미나 과제 Oct 8, 2024
@daehwan2da
Copy link

고생하셨습니다~

이모지 처리

정규식을 사용해서 처리하였다. But, 이렇게 처리하면 너무 간단해서 팟짱님의 다른 의도가 있지 않았을까? 라는 생각이 든다..!

  • 좋은 방향을 고민한것같아요. 실제로 👍🏻 이런 이모지가 들어갔을때도 의도한대로 동작하였을까요?

✅ 메모리 할당 (1)문자열 리터럴 : String Constant Pool 사용
✅ 메모리 할당 (2)new 키워드 사용 : Heap 영역

  • String ConstantPool 에 대한 구체적인 동작 원리랑, jdk 버전별 String 처리 방식 변화 과정도 고민해보면 좋을것같아요.

@choyeongju choyeongju changed the title 와인잔조 5조 1차 세미나 과제 [와인잔 5조] 세미나 과제 Oct 25, 2024
@daehwan2da
Copy link

고생하셨습니다~ 정리 잘해서 자기꺼로 만드시길바랄게요.

@choyeongju choyeongju changed the title [와인잔 5조] 세미나 과제 [와인잔 5조] 1차 세미나 과제 Nov 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants