전체 글 140

[자바 스프링] 멀티 모듈 설계

문제 발단 당시 SellWe 프로젝트를 기획할 때, HTTP 통신과 웹소켓(WS) 통신을 사용할 계획은 있었지만 서버의 구성과 설계적인 측면을 고려하지 않았습니다. 결국 프로젝트에서는 이러한 기능들을 하나의 서버에 넣기로 결정하였습니다. 그러나 웹소켓의 특성상 지속적인 연결로 인해 더 많은 리소스를 소모하게 되어 서버의 안정성을 위해 다른 대안을 고려하게 되었습니다. 첫 번째 대안은 Nginx를 이용한 로드 밸런싱 기술을 사용하는 것이었습니다. 하나의 서버에 두 기능을 구현하고 Nginx를 통해 클라이언트를 분배하는 방식을 고안했습니다. 하지만 Nginx와 로드 밸런싱에 대한 지식 부족으로 다른 대안을 찾아보게 되었습니다. 세 번째 대안은 프로젝트를 기능별로 나누어 개발하고, 각각의 기능을 다른 서버에 ..

[ShellWe 프로젝트] ERD 및 엔티티 연관관계 최적화

이전 개인 프로젝트 포스트(https://mason-lee.tistory.com/159)와 마찬가지로 필요없는 양방향 관계매핑을 없애고 ERD 설계를 다시 해보려 한다. 설계를 다시 해보기에 앞서, 지난 포스트에서는 다루지 못했던 단방향 매핑을 적극 활용해야 하는 이유에 대해 알아 보려한다. 양방향 매핑보다 단방향 매핑을 더 선호하는 이유 단순성과 가독성: 단방향 매핑으로 코드와 매핑 구조를 더 단순하게 유지할 수 있다. 양방향 매핑은 두 개의 엔티티가 서로를 참조해야 하므로 코드가 복잡해지고 가독성이 떨어진다. 데이터 일관성 유지: 양방향 매핑에서는 한쪽 엔티티를 수정할 때 다른 엔티티도 업데이트 해야한다. 성능 향상: 양방향 매핑은 객체 그래프를 탐색할 때 불필요한 쿼리가 발생할 수 있다. 예를 들어..

[게시판 프로젝트] 테이블 설계 및 엔티티 관계매핑에 대한 회고

이번 포스트는 제 개인 프로젝트인 게시판 만들기를 모든 코딩 작업을 마치고 난 후 회고 목적으로 작성하는 포스트입니다. 사실 해당 프로젝트를 완료했을 때, 기능 하나하나에 공들인 만큼 모든 기능들이 순조롭게 작동되어 스스로가 너무 뿌듯했다. 그러나 두달이 지난 현재, 다시 코드를 살펴보니... 엔티티 하나만 살펴봤는데도 답답함이 느껴진다. @Entity @NoArgsConstructor @Getter @Setter public class Member extends Auditable { public Member(Integer memberId) { this.memberId = Long.valueOf(memberId); } @Id @GeneratedValue(strategy = GenerationType.ID..

@ElementCollection 그리고 @Embedded와 비교

Embedded Type을 공부하던 중 @ElementCollection과 @Embedded가 비슷하면서도 다른점을 느껴 개인적으로나마 간략하게라도 정리를 해야겠다고 생각하여 블로그를 작성하게 되었다. 먼저 @ElementCollection에 대해 알아보자 (@Embedded의 사용법은 이전 포스트에 기재: https://mason-lee.tistory.com/157 ) @ElementCollection 이란? @ElementCollection은 JPA에서 사용되는 어노테이션으로 단순한 컬렉션(리스트, 맵, 셋 등)을 사용하여 단일 혹은 복합적인 값 타입(int, String 등)을 저장할 때 사용되는 연관관계 매핑의 한 종류이다. 만약 복합적인 값 타입을 저장할 때에는 @Embeddable을 사용하여 ..

@Embedd를 활용한 관계 매핑

문제 발단 개인 프로젝트로 만든 게시판의 처음 계획했던 모든 기능들을 성공적으로 완성한 뒤 회고 차원에서 테이블 설계를 좀더 간략화 시킬 수 있는 방법이 없을까 고민하던중 Embedded Type을 알게 되어 알아보게 되었다. Embedded Type이란? Embedded Type은 JPA에서 사용되는 개념으로 엔티티의 일부 속성을 별도의 테이블로 분리하지 않고 하나의 테이블에 내장하는 방식이다. 장점 코드의 재사용: 여러 엔티티에서 공통된 속성을 임베디드 타입으로 묶어 재사용할 수 있다. 객체지향적 설계: 여러 속성을 하나의 객체로 분리하여 더욱 객체지향적으로 설계할 수 있다. 데이터베이스 스키마 최적화: 중복 데이터 저장을 최소화하여 데이터베이스 스키마를 깔끔하게 유지할 수 있다. 복잡성 감소: 일부..

./gradlew: /bin/sh^M: bad interpreter: No such file or directory

문제 발단 깃헙 Actions로 자동 배포화를 진행하던 중 아래와 같은 에러가 발생했다. 문제 해결 시도 처음에는 gradlew 파일을 못찾는건가 싶어 빌드 이전 같은 디렉토리에서 'ls' 명령어를 실행하도록 해봤는데 분명 해당 디렉토리에 gradlew 파일이 존재했다. 결국 구글에 검색해보니...(그냥 구글이 답이다 고집부리지말고 검색하자) /bin/sh^M: bad interpreter: No such file or directory 에러는 윈도우에서 쉘스크립트 파일을 작성하게되면 줄바꿈시 "^M" 문자가 들어가는데 이때문에 생긴 에러라고 한다. 실제로 "vi -b gradlew" 명령어(vi 편집기의 바이너리 모드로 gradlew에 접근)를 통해 gradlew 파일에 접근해보니 줄바꿈이 이루어진 곳..

스레드 풀 관리 - new ThreadPoolTaskExecutor()

기능 구현중 비동기 처리를 해야될 상황이 생겨 new Thread().run()을 이용하여 비동기 처리를 진행 했었다. 하지만 이경우 스레드를 반복적으로 생성, 삭제가 이루어저 오버헤드가 발생하게 되어 다른 방법을 찾아 적용하게 되었다. 일단 @Async 어노테이션을 사용해도 비동기 처리가 가능하지만 아무 설정없이 사용한다면 위와 마찬가지로 그저 스레드를 생성, 삭제 할뿐이었다. 그래서 스레드 풀을 위한 설정을 해주어야 했다. 스레드 풀 설정 bean 등록 @Configuration @EnableAsync // Application이 아닌, Async 설정 클래스에 붙여야 함. public class SpringAsyncConfig extends AsyncConfigurerSupport { @Bean(n..

DefaultHandshakeHandler를 이용하여 Websocket session에 유저 정보 담기

사건 발달 현재 어플리케이션은 사용자가 웹소켓 서버를 통해 전송하는 모든 메시지와 관련 정보를 데이터베이스(DB)에 저장하는 방식으로 동작하고 있었다. 이로 인해 사용자가 메시지를 전송할 때마다 매번 사용자의 정보를 DB에서 조회하거나 해당 사용자의 정보를 메시지에 포함하여 전송해야 하는 번거로움이 있었다. 따라서 서버의 최적화와 보안상의 이유로 더 효율적인 방법을 고려해야만 했다. 이에 따라, 사용자의 정보를 SecurityContextHolder에 저장된 Principal 객체에 담아 Websocket의 세션(session)에 저장하기로 결정하였다. 그러나 Websocket의 세션 객체에는 setPrincipal과 같은 메서드가 없어 Principal 객체를 세션에 저장하기 위해서는 TCP 3-way..

메인 프로젝트 'ShellWe' 일지

프로젝트 목표 물물교환 서비스 플랫폼 "ShellWe" 개발 프로젝트 기간 4주 개발 인원 6명(프론트 3명, 백엔드 3명) 프로젝트 아이템 선별 메인 프로젝트를 진행할때가 되어서 어떤 서비스를 개발을 해야할까?... 계속해서 고민해봤지만 도무지 아이디어가 떠오르지 않았다. 새롭고 신선한 서비스를 구상하고 싶었지만 생각해낸 아이디어들이 이미 존재하는 웹 혹은 앱 서비스들의 하위 버전에 속하지 않았다. 결국 내 기억에 따라 과거에 내가 불편했던 것들 혹은 아쉬웠던 일들을 생각해보고 그에 맞는 서비스를 개발해보자 생각하던 중 하나의 기억이 떠올랐다. 몇 개월 전, 친구가 새 애플워치를 사게되면서 이전에 사용하던 애플워치를 중고로 팔려고 하고있었다. 나는 애플워치를 구입하고 싶었지만 오랜 개발 공부로 최대한 ..