배경현재 개발 중인 회사 블로그 서비스는 관리자만 게시물을 작성할 수 있으며 일반 사용자들은 조회만 할 수 있다.관리자는 게시물을 비공개 처리할 수 있으며 비공개된 게시물에는 일반 사용자들이 접근하지 못한다.관리자가 게시물을 작성할 때는 별도 에디터를 사용하며 db에는 에디터에서 작성된 html이 저장된다.관리자가 게시물 본문에 첨부한 파일은 클라우드 스토리지에 보관된다. 버킷의 접근 권한과 비공개 일관성버킷의 접근 범위를 public으로 두면 비공개 게시물의 첨부 파일도 url만 있으면 접근하여 조회할 수도 있다.이는 게시물 비공개의 일관성을 보장하지 않으며 파일도 비공개일 것이란 사용자의 예상을 깨는 것이라 판단해버킷 접근 권한을 private으로 두기로 결정했다. (스포하자면 결국 public으로 ..
학습 배경사내 블로그 서비스의 개발 환경을 구축하던 중 certbot과 dns 챌린지 방식을 활용해 https 설정을 했고,그 과정에서 생긴 궁금증들을 해결해보았다. Certbot이란?Certbot은 Let's Encrypt라는 CA에서 SSL 인증서 발급 및 관리를 위해 제공하는 오픈소스 도구다.CA(Certificate Authority)는 말 그대로 https 인증을 하는 기관이고, Let's Encrypt는 CA 종류 중 하나이다. SSL 인증서의 목적은 무엇일까?SSL 인증서는 이 서버가 해당 도메인의 진짜 주인이다라는 것을 인증한다. 도메인의 주인이라는 것을 왜 인증해야 할까?공격자가 중간에서 브라우저의 요청을 가로채 진짜 서버인척 흉내를 낼 수 있기 때문이다.이를 MITM(Man in the..
문제 상황DailyBlog 내 게시글 목록을 새로 고침하면 0.5초 정도 지연되는 현상을 발견했다.개발자 도구로 응답 시간을 확인해보니 사용자가 충분히 체감할 수 있는 400~900ms로 측정되었다.블로그 서비스에서 게시글 목록이 늦게 로딩되는 현상은 사용자 경험을 크게 해칠 수 있기 때문에 이를 해결해보기로 했다. 시도한 것우선 개발자도구-네트워크 탭 내 Waterfall 항목을 확인해보았다.요청 시간 817ms 중 서버 응답 시간의 비율이 97%(807ms)였다. 다음으로는 django 애플리케이션 로그를 확인해보았다. django 애플리케이션에서는 별도로 구현한 LoggingMiddleWare를 통해 요청의 진입~탈출까지의 시간을 duration이라는 필드로 로그에 기록하고 있다. 해당 요청 로그..
학습 배경최근 블로그 클론코딩(리버스 엔지니어링)을하며 nginx에 https를 설정하는 작업을 했다.이전 프로젝트부터 https를 몇 번 다뤘지만 한번도 내부를 들여다 본 적이 없어 이번 기회에 알아보았다. https란?패킷을 평문으로 송신하는 http와 다르게 https는 암호화하여 송신한다.암호화 되어있기 때문에 패킷 송신 중 누군가가 탈취/감청을 해도 패킷의 내용을 알 수가 없다. https 통신에서는 클라이언트가 패킷을 암호화하여 송신하면 서버가 이를 수신하고 복호화한다.(응답 시에는 그 반대) 데이터를 암호화/복호화하기 위해서는 키가 필요하다.https를 알아보기 위해서는 대칭키와 비대칭키에 대해 알아야한다. 대칭키는 하나의 키를 가지고 암/복호화를 모두 할 수 있다. 말그대로 대칭이다.반대로..
문제 상황서비스 레이어의 단위 테스트를 위해 TestRepository 코드를 작성하던 중 save() 내부에서 파라미터로 받은 엔티티의 id를 설정해주어야 했다. 하지만 id 필드의 접근 제어자는 private이고, setter를 열어두지 않았기 때문에 TestRepository에서 id값을 설정할 수가 없었다.public class GroupTestRepository implements GroupRepository { private Map storage = new HashMap(); private long sequence = 0L; @Override public Group save(Group group) { if (group.getId() != null) { ..
문제 상황 JpaRepsitory의 구현체인 GroupJpaRepository에 직접 의존하고 있는 GroupService를 단위 테스트하고자 한다.@Service@Transactional(readOnly = true)@RequiredArgsConstructorpublic class GroupService { private final GroupJpaRepository groupJpaRepository; ...} 시도한 것 1. 실제 db를 사용해 통합 테스트 / 외부 Mocking 라이브러리 사용테스트하고자 하는 대상이 repository 구현체에 의존하고 있기 때문에 실제 repository 구현체를 사용하고 데이터베이스와 연동해 통합 테스트를 하거나, Mockito와 같은 외부 라이브러리를 사용..
문제상황@WebMvcTest Controller 단위테스트를 마친뒤, Jpa Auditing 기능을 사용하기 위해 StockMateApplication에 @EnableJpaAuditing 애너테이션을 추가하자 기존에 성공하던 테스트들에서 다음과 같은 에러가 발생했다. 에러 메세지를 보아하니 jpaMappingContext 빈이 없어 발생하는 문제같다. 시도한 점@WebMvcTest는 컨트롤러 레이어를 테스트하는데에 특화되어있어 Controller, RestController, Resolver 등 Spring MVC와 관련된 빈들만 자동으로 등록한다. Testing Spring Boot Applications :: Spring BootTo test whether Spring MVC controller..
왓슈 프로젝트를 진행하며 비즈니스 로직을 어디에 작성해야하는 지에 관해 고민을 많이 했었다. "가입 신청 취소" api에서는 일련의 과정을 거친 뒤 가입 신청 엔티티의 status를 canceled로 바꿔주어야 한다.이때 ClubJoinRequest 엔티티의 status 필드를 어디에서 바꿔줘야 할까?1. 외부(ex_service 레이어)에서 status 필드를 직접 변경한다.2. 엔티티 내에서 status 필드를 직접 변경한다. 관련해서 다른 블로그도 찾아본 뒤 엔티티 내에 비즈니스 로직을 위치시키자는 결론을 지었으나 왜 그래야하는 지에 대해 스스로에게 물었을 때 명확하게 답변을 할 수 없었다. 그러다 최근 조영호님의 객체지향의 사실과 오해를 읽고나서 깨달은 바가 있어 생각을 정리해보고자 한다. 객체지..
문제 상황모임 관리 프로젝트의 모임 관련 api를 개발하다가 다음과 같은 문제를 직면했다.1. 매번 club이 존재하는지 체크해주어야한다.2. 매번 로그인 유저가 이 club의 멤버인지 체크해주어야 한다.3. 매번 로그인 유저가 이 club의 관리자인지 체크해주어야 한다. (관리자 api인 경우)4. 매번 로그인 유저가 이 club에 가입 이후 처음 방문했는지 체크해주어야 한다. 클럽에 관련된 api마다 1, 2, 3, 4의 중복 코드가 발생한다. 해결방안중복되는 공통 관심사를 한번에 처리하고자 하였다.조금 찾아보니 필터, 스프링 인터셉터, AOP 로 공통관심사를 처리할 수 있었고,나는 스프링 인터셉터(Spring Interceptor)를 사용하여 이번 문제를 해결하고자 하였다. 스프링 인터셉터란 ?스..
