25년 2월을 돌아보며

Published
February 28, 2025
Last updated
Last updated February 20, 2025
Tistory
Category

Week 6

250203(Mon)

250204(Tue)

     

    250205(Wed)

     
     

    250208(Sat)

    • 솔리드 커넥션 서버 코드 리뷰

    Week 7

    250211(Tue)

    • 소마 지원서 제출…
    • 솔리드 커넥션 신규 대학 추가
     

    250212(Wed)

    • 솔리드 커넥션 웹 개발
      • 애플 로그인 추가
     

    250114(Fri)

    • 솔리드 커넥션 웹 개발
      • api 엔드포인트 변경에 따른 수정
      • 애플 로그인 버그 수정
      • 웹 stage 환경 분리/구성
    • 솔리드 커넥션 모니터링 인프라 구성
     

    250115(Sat)

    • 솔리드 커넥션 웹 개발
      • api 변경에 따른 수정
      • 수많은 버그 리포트와 버그 수정…
    • 솔리드 커넥션 어드민 페이지 개발
      • 일반 react 앱으로 개발 예정
      • 기본 패키지 설치, lint/format 설정
    • 솔리드 커넥션 앱 개발
      • 스캐폴딩 색 문제, 확대 문제 해결

    250116(Sun)

    • 솔리드 커넥션 웹 개발
      • 신규 홈 화면 컴포넌트 추가
      • 지원 페이지 다시 추가
    • 솔리드 커넥션 앱 개발
      • 빌드 후 배포… ios 배포는 잘 모르겠다
     

    Week 8

    250117(Mon)

    • 솔리드 커넥션 웹 개발
      • stage환경 env 설정
      • Vercel에서 .env.production은 자동으로 적용되서 Preview에는 .env.development가 자동적용 되지 않을까? 했지만 어림도 없다
      • favicon 추가
        • svgr 때문에 icon.svg 오류, 고칠방법이 있겠지만 그냥 icon.png로 변경. 이게 문제해결이지 ㅇㅇ
      • 사파리 폰트문제 수정
      • 성적 공유 페이지 캐싱때문인지 오류, 서버쪽에 이슈 리포트
      • api 엔드포인트 오류 수정
      • 덧글 새로고침 안되는 버그 수정
        • router.refresh()의 원리를 알게되었다
      • PUT과 대비한 PATCH의 장점을 확실히 느꼈다
        • 이미지 변경이나, 중복 닉네임 변경등…
      • 서버사이드 렌더링 revalidate 새로고침 추가(뉴스 페이지)
     
    • 프로그래머스 풀이
      • Lv.1 /연습문제/과일 장수
      • Lv.2 /2021 KAKAO BLIND RECRUITMENT/순위 검색
        • 숫자를 제외하고는 총 3 * 2 * 2 * 2 로 그렇게 많은 경우의수가 있지는 않다
        • 트리형태로 탐색 가능하게
        • 다만 숫자를 그냥 linear하게 탐색했더니 시간초과가 났다
        • 큰 차이가 나지 않을꺼라 생각했는데 조건에 따라 크게 상관 있을 것 같긴 하다
        • 전체적으로 파이썬 PS에 익숙해지는 기회가 되었다. bisect도 오랜만에 써보고, 문법도 다시 한번 써보게 됐다
     
    • Celery 오류 해결
     
     

    250118(Tue)

    • mc-archieve 개발
      • MappedSuperclass를 이용한 BaseEntity 추가
    • Celery 공부
      • prefetching과 이의 단점에 관해
      • ACK 조건과 acks_late 그리고 RabbitMQ를 사용하지 않는 환경에서의 visibility timeout에 관해
     
    • 자바 ORM 표준 JPA 프로그래밍 - 기본편 학습
      • 값 타입
        • 엔티티 타입: @Entity로 정의한 객체
          • pk값으로 관리되기 때문에 지속적으로 추적하고 관리 가능
        • 값 타입: 자바 기본 타입(int, double 등), 래퍼 클래스(Integer, Long 등), String 등
          • 생명주기를 엔티티에 의존한다(회원을 삭제하면 이름, 나이 필드도 같이 삭제)
          • 같은 값이라고 공유해서는 안됨(이름을 바꾸면 동명이인의 이름도 같이 바뀐다던지)
          • primitive type은 항상 값을 복사하니 ok
          • 래퍼클래스나 String등은 자바에서 공유를 막을 수는 없기에 변경을 못하게 해서 side effect를 막는다
        • 임베디드 타입
          • 회원 정보중 주소(city, street, zipcode)를 분리해서 관리하려면 따로 만들어서 @Embeddable를 붙이기
          • 이를 사용하는 Member쪽에서는 @Embedded 붙여주기
          • 기본 생성자 필수
          • @Embeddable public class Address { private String city; private String street; private String zipcode; public Address() { // 기본생성자 필수 } } public class Member { @Id @GeneratedValue @Column(name = "MEMBER_ID") private Long id; @Column(name = "USERNAME") private String username; @Embedded private Address homeAddress; }
          • 장점: 재사용, 높은 응집도
          • 객체와 테이블을 세밀하게 매핑가능
            • 잘만든 ORM 앱은 테이블보다 클래스의 수가 더 많다
          • @AttributeOverride/@AttributeOverrides 로 속성 재정의 가능
        • 값 타입과 불변 객체
          • 임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험함
            • primitive, wrapper, String은 막혀있으니 괜찮지만 임베디드는 직접 정의한 객체이기에 공유/수정이 가능하니 주의
          • 불변 객체(immutable object)
            • 생성자로만 값을 설정하고 수정자를 만들지 말자
            • Integer, String등도 자바가 제공하는 불변 객체
            • 바꾸고 싶으면 새로 객체를 생성하자
          • 값 타입 컬렉션
            • @ElementCollection, @CollectionTable 을 이용
            • 값 타입을 하나 이상 저장할 때 사용
            • 값 타입을 소유한 엔티티의 생명주기를 따라간다
            • 지연로딩으로 작동
            • 식별자가 없기 때문에 매번 모든 값 타입 컬렉션은 지우기 다시 쓴다
            • 모든 컬럼이 식별자가 되기에 null x, 중복저장 x
            • 즉 실무에서는 값 타입 대신 1:N을 고려하는 편
      • 객체지향 쿼리 언어1 - 기본 문법
        • 소개
          • JPA에는 다양한 쿼리방법이 있다: JPQL, QueryDSL, 네이티브 SQL, JDBC API
          • JPQL: 객체지향 SQL
            • JPA를 사용하면 엔티티 중심으로 개발하는데, 검색쿼리를 날릴 때 문제가 있다. 왜냐면 모든 DB를 객체로 만들고 검색하는 것은 불가능하고 필요한 데이터만 DB에서 불러와야하기 때문
            • JPA는 SQL을 추상화한 객체 지향 쿼리 언어 JPQL을 제공
            • List<Member> result = em.createQuery( "select m from Member m where m.username like '%kim%'", Member.class ).getResultList();
            • 단점: 단순 문자열이기에 동적쿼리 생성이 어려움. 실무에서는 잘 쓰이지 않음
          • QueryDSL: 동적쿼리 작성이 편리, 컴파일 시점에 문법오류를 찾을 수 있다. 권장.
          • JDBC를 직접 사용할 경우에는 영속성 컨텍스트를 직접 flush 해줘야한다
            • SQL을 실행해주기전에 수동 flush
        • 기본 문법과 쿼리 API
          • select m from Member as m where m.age > 18
          • 엔티티와 속성은 대소문자 구분
          • JPQL 문법은 대소문자 미구분
          • alias는 필수지만 as는 생략가능(m)
          • TypeQuery: 타입이 명확할 때, Query: 타입이 명확하지 않을 때
          • query.getResultList(): 결과 하나 이상, query.getSingleResult(): 결과가 하나
          • 파라미터 바인딩: 이름 기준 또는 위치 기준으로 적용 가능. 아래는 이름 기준 예시
          • Member result = em.createQuery("select m from Member m where m.username = :username", Member.class) .setParameter("username", "jayden") .getSingleResult();
        • 프로젝션
        • 페이징
          • setFirstResult(int startPosition).setMaxResults(int maxResult) 메서드 체이닝 가능
        • 조인
        • 서브쿼리
        • JPQL 타입 표현과 기타식
        • 조건식(CASE 등등)
        • JPQL 함수
      • 객체지향 쿼리 언어2 - 중급 문법
        • 경로 표현식
          • 상태 필드(state field): 단순히 값을 저장하기 위한 필드(ex: m.username)
            • 경로 탐색의 끝, 탐색 X
          • 연관 필드(association field): 연관관계를 위한 필드
            • 단일 값 연관 필드: @ManyToOne, @OneToOne, 대상이 엔티티(ex: m.team)
              • 묵시적 내부 조인(inner join) 발생, 탐색 O
            • 컬렉션 값 연관 필드: @OneToMany, @ManyToMany, 대상이 컬렉션(ex: m.orders)
              • 묵시적 내부 조인(inner join) 발생, 탐색 X
              • FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능
          • 예제
            • select o.member.team from Order o: 성공
            • select t.members from Team t: 성공
            • select t.members.username from Team t: 실패
            • select m.username from Team t join t.members m: 성공
          • 가급적 명시적 조인 사용
        • 페치 조인 1 - 기본
        • 페치 조인 2 - 한계
        • 다형성 쿼리
        • 엔티티 직접 사용
        • Named 쿼리
        • 벌크 연산
     

    250219(Wed)

    • mc-archieve 개발, 스프링 공부
      • @ManyToOne(optional=false) 과 @JoinColumn(nullable=false) 차이
        • optional은 JPA 객체에 관한 것, nullable은 테이블에 관한것. 둘을 일치시키지 않을 이유가 없어보인다. 둘다 적용해주기
      • 엔티티 리팩토링
        • Many쪽을 연관관계의 주인으로 설정, ManyToOne에서 지연 로딩 설정
        • Image를 엔티티에서 Embedded로 전환
        • 유저 관련 엔티티는 OneToOne이 많다
          • password, player 분리는 필수라 생각하고, profile 분리는 나의 취향…
          • 프로필 분리시 @MapsID 로 user와 profile id를 일치시켰다. 나중에 더 공부해볼 것
        • Profile에서 Image를 재활용
          • 굳이 필요없다 생각했는데, @AttributeOverride로 컬럼명 재지정해줘도 될듯. 나는 이정도면 ok라 생각. 어짜피 Profile도 분리해두었으니
      • 레포지토리 구현
      • OneToOne에서 Lazy를 쓴다면 어떨까?
        • player와 password는 lazy가 맞다 생각해서 분리했다. password는 인증때만 쓸거고, player는 항상 필요한게 아니니. profile은 하나처럼 쓰고자 EAGER로 했다(기본값)
        • 다만 one to one에서 연관관계의 주인이 아닌쪽은 Lazy로 설정해도 Eager로 된다는 말이 있다. 큰 문제는 아닌듯. 어짜피 반대 방향에서는 거의 항상 불러 올 것 같아서
      • 컨트롤러/서비스 로직 구현
        • 스프링 빈을 주입 받을 때 → private final 해주기
     
    • 솔리드 커넥션 모니터링 설정
       

      250220(Thu)

      • 솔리드 커넥션 웹 개발/버그 수정
        • 성적 제출 타입 문제
          • Enum 추가하고 성적 종류 추가해서 해결
        • 성적 인증 거절 사유 알림창 추가
        • 예정: 신규 홈 화면 적용
       
      • 솔리드 커넥션 서버
        • Sentry 설정
       
      • SQL PS
        • 피곤해서 SQL 문제 풀이. 문법부터 조금씩 공부해나가자…
        • 결과에 문자열 추가하려면 CONCAT
          • SELECT CONCAT(MAX(F.LENGTH), "cm") AS MAX_LENGTH
        • 반올림 하려면 ROUND(value, int) 이때 int 가 2라면 소수점 2자리까지 보임(3자리에서 반올림)
        • null인 값을 특정값으로 처리하려면 ISNULL이나 COALSCE. COALSCE는 여러값을 한번에 처리 가능.
          • SELECT ROUND(AVG(COALESCE(F.LENGTH, 10)), 2) AS AVERAGE_LENGTH