노션에 정리해놓았다가 드디어 블로그로 옮기는 작업을 하고 있다.이번에 쓰는 글을 우리 서비스의 핵심기능인 이메일 서버관련 글이다. 먼저 우리 서비스가 모르시는 분이 있을 수도 있는데 이 서비스를 만든 가장 큰 이유 중 하나즉 페인포인트는 여러 메일이 섞인다는 것이다. 먼저 예시를 보자위 이미지는 제 받은메일함입니다. 메일 종류를 보면 결제 내역, 뉴스레터, facebook, github 등등 뒤죽박죽 섞여있습니다. 이를 정리하기 위해 메일함을 만들어서 분류하기도 귀찮습니다. 그렇다고 뉴스레터 전용 이메일을 만든다? 뉴스레터 이메일 갔다가 다시 원래 이메일 갔다가 하기가 번거롭다. 여기 현재 서비스를 보면 이렇게 이메일이 도착하면 오늘의 뉴스레터 페이지에서 볼 수 있다. 이 화면을 보여주면 ..
분류 전체보기
봄봄의 상황현재 봄봄은 300명이 넘는 회원이 쓰고 있는 서비스다.“우테코 끝나면 이거 그냥 접는 거 아니야?”라는 질문을 여러 번 들었는데,처음 기획할 때부터 우리 팀의 목표는 분명했다.“실험용 토이 프로젝트 말고, 진짜 계속 운영하는 서비스 한 번 만들어보자.” 처음 합을 맞출 때도 그 얘기를 했고,우테코가 거의 끝나갈 즈음에 내가 다시 한 번 팀원들에게 물어봤다.“진짜야? 우테코 끝나도 이거 계속 한다?” 그리고 모두가 “당연하지” 쪽에 손을 들어줬다.그런데 한가지 문제가 있다. 바로 우리 서비스는 아직 수익이 없다는 점이다.수익 모델에 대한 아이디어는 몇 가지 가지고 있지만, 거기까지 가려면 아직 시간이 꽤 걸린다.그 전까지는, 말 그대로 버티는 힘이 중요하다. 버티려면 결국 고정비용을 줄여야 한..
들어가며뉴스레터 검색 기능을 재설계 및 개선하다가뜻밖에 먼저 건드려야 할 친구를 하나 발견했다. 바로 HTML 태그였다. “본문은 텍스트가 중요한데, 왜 굳이 태그까지 다 들고 있어야 하지?”라는 질문에서 시작된 고민과, 그걸 정리해 가는 과정들을 한 번 적어봤다. 뉴스레터 검색, 첫 번째 장애물: HTML 태그우리 서비스에서 다루는 뉴스레터는 이런 식으로 생겼다. 모든 뉴스레터는 HTML 형태로 들어오고, DB에는 대략 이런 형태로 저장된다. 검색 기능을 개선하면서, 이 `contents` 칼럼에서 HTML 태그를 걷어내는 작업이 필요해졌다. 현재 `contents`에는 HTML 태그를 포함한 본문 전체가 들어 있다.문제는 이 칼럼의 길이가 보통 8,000자 ~ 15,000자 정도라는 점이다. 검색 성..
👋 들어가며처음에는 검색을 정말 단순한 문제라고 생각했다.그냥 검색어만 넣으면 결과가 쭉 나오면 되는 거 아닌가? 그런데 직접 구현하고, 부하 테스트까지 돌려 보니생각보다 함께 고려해야 할 것들이 훨씬 많다는 걸 알게 됐다.그리고 아마 앞으로도 계속 고민할 지점이 남아 있을 것 같다. 지난 몇 달 동안 검색 기능을 조금씩 만들고 고쳐 오면서 했던 생각들을드디어 글로 정리하게 되었다. 🚀 우리 서버의 검색기능 봄봄 서비스에는 “내가 받은 아티클 안에서 검색하는 기능”이 있다.처음 구현은 아주 단순했다.WHERE title LIKE '%:keyword%' OR content LIKE '%:keyword%'즉, 제목이나 본문에 keyword가 어디에라도 포함되어 있으면 검색 결과에 나오도록 한 것이..
현재 우리 서버는 한창 알림을 만드는 중이다. 이 과정에서 알림을 보내기 위한 기본 정보들이 DB에 저장이 안 되는 일이 발생했다.what?분명 코드적으로 문제가 없는 것 같은데 왜 저장이 안되는 걸까?? 처음에는 이유를 알 수 없었다. @TransactionalEventListener public void onArticleArrived(ArticleArrivedEvent event) { try { ArticleArrivalNotification articleArrivalNotification = ArticleArrivalNotification.builder() .articleId(event.articleId()) ..
보호되어 있는 글입니다.
보호되어 있는 글입니다.
(이 글에서는 OSIV/OEMV 모두 OSIV로 지칭합니다)(이 글을 작성할 수 있게 소스를 준 노랑에게 감사합니다) 우연히 노랑이라는 크루를 통해 `@Transactional`을 붙이지 않았는데 더디체킹이 된다는 소리를 들었고 실제로 Query를 보니 update를 하지 않았는데 update가 되었다. 처음 봤는데 신기했다. 동시에 무엇때문에 그러는지 궁금해지기 시작했다. 문제의 코드는 아래와 같다. public void cancelReservationById(final long id) { waitingRepository.findFirstByReservationIdOrderByCreatedAtAsc(id) .ifPresentOrElse( (..
레벨 2 미션을 처음 했을 때, 습관처럼 컨트롤러에서 반환 값을 ResponseEntity로 감싸서 처리했다.예를 들어, 아래와 같은 코드였다.@GetMapping("/users/{id}")public ResponseEntity getUser(@PathVariable Long id) { return ResponseEntity.ok(userService.findUser(id));}사실 이전 프로젝트에서도 큰 고민 없이 이렇게 사용했고, "왜?"라는 질문조차 던지지 않았다.미션을 제출한 후에도 자연스레 의심 없이 지나쳤다. 그러다 우연히 다른 크루의 코드 리뷰를 보며 처음으로 궁금증이 생겼다. 이때부터 생각했다. `ResponseEntity`가 무엇이고 왜 써야 하지? 안 쓰면 어떻게 될까? 🚀..