본문 바로가기

전체 글139

MIT 인턴 기술스터디 후기 MIT 대학생들이 여름방학을 맞아 8주간 네이버 체험형 인턴십을 진행했다. 그중 한명(이하 A)이 우리팀에 오게됐다. 왜 FAANG 같은 빅테크 기업에서 인턴을 안하고 네이버로 왔는지 너무 궁금했다. A 는 부모님이 모두 한국에 계셔 겸사겸사 왔다고 했다. 그리고 한국에서 지냈던 시간이 많아 한국말도 잘 했다. 나는 EDA 를 주제로 A 와 1:1 스터디를 진행 했다. 사실 이 스터디에 개인적인 목적은 따로 있었다. 나의 일을 나의 언어로 잘 설명할 수 있는지 테스트 해보고 싶었다. 그래서 8주 동안 내가 개발하고 있는 EDA 를 정리하고 발표했다. 물론 A 의 전공이 수학이고 컴퓨터 수업은 몇개 안들은 상태였기 때문에 주제가 너무 어려울수 있겠다는 생각도 했다. 그래도 우리 시스템에서 발생할 수 있는 .. 2023. 8. 13.
EDA 에서 Event 중복 발행(동시성 이슈) 먼저 spring application 서버는 kafka 메세지를 consuming 하고 producing 하는것을 반복하는 구조다. 왜 Event 가 중복 발행됐는지를 이해하려면, Kafka 이벤트 발행과 DB 저장(redis) 트랜잭션 을 이해해야 한다. 메세지 유실을 막기위해 db update 를 두번하는데 그 과정이 이해 안가면 아래 흐름을 받아들이기 어렵다. 핵심은 9번(redis 에 update) 이 끝나기전, 10번에서 order 가 조회된다는 부분이다. consume 타이밍을 제어할 수 없으므로 결국 reids db lock 이 필요하다. 9번(redis 에 update) 이 끝날 때까지 lock 을 잡고, 10번(order 조회) 을 기다리도록 해서 문제를 해결했다. lock 기능은 s.. 2023. 7. 22.
WebClient 에서 raw response body 로깅 모니터링 부서에서 특정 webClient api 요청과 응답 로그를 찍어주길 희망했다. 해당 webClient 는 retrieve 를 사용하고 있었기 때문에 doOnSuccess 와 onErrorMap 에 성공/실패 로그를 남겼다. cf) 응답 response body 는 xml 로 전달해주는 api 다. this.webClient.get() .uri(uri) .retrieve() .bodyToMono(YbsResponse.class) .doOnSuccess(ybsResponse -> { log.info(시간, uri, ybsResponse, 성공메세지) }) .onErrorMap(throwable -> { log.info(시간, uri, throwable.getMessage(), 실패메세지) }) ... 2023. 7. 15.
주문서 전환 프로젝트 8부능선 내가 담당하는 네이버페이 주문서 전환 프로젝트(이하 신주문서)는 크게 3개 모듈로 이뤄졌다. 그래서 순차적으로 전환 시키는게 우리팀 미션이다. 우리는 작년 12월에 1차 전환을 끝냈고, 이번주에 2차 전환도 마무리지었다. 드디어 마지막 최종 보스(스마트스토어용 주문서)만 남은 상태다. 스마트스토어는 1,2차 때보다 사용자 트래픽이 훨씬 높고 상품 종류와 결제방식도 다양하다. 하지만 큰 장애없이 전환할 수 있을거라 생각한다. 우리는 동적으로(애플리케이션 배포없이) 사용자 트래픽을 제어할 수 있는 장치를 구축해놨기 때문에 지난 1,2차 때도 잘 전환할 수 있었다. 처음 시작은 전체 사용자 중 1% 만 신주문서를 경험하게 하고, 우리는 쌓이는 로그들을 집중 모니터링 한다. 모니터링하면서 에러가 발생하거나 조금.. 2023. 6. 24.
유난한 도전 그동안 토스에 대한 이야기는 여러 경로로 많이 들었다. 하지만 그동안 실패했던 사업 이야기는 이 책을 통해 처음 접할 수 있었다. 수많은 실패에도 불구하고 유니콘 기업이 된 토스 역사는 정말 재밌었다. 악명? 높은 기업 문화에 대해서도 이해할 수 있게 됐다(머리로만). 운도 정말 중요하지만 서비스가 성공하는데는 다 이유가 있는거 같다. 처음엔 토스 창업자를 찬양하는 책일까 살짝 걱정했다. 하지만 부족한 모습, 실수하는 모습들을 솔직하게 담아내서 더 매력적으로 느껴졌다. 물론 모든게 좋아보인건 아니다. 서로 직설적으로 내뱉고 틀리면 그때 사과하고 인정하는 에피소드를 들었을 땐 별로였다. 생사의 갈림길에 있는 상황이니 어느정도 이해해도 나같은 사람은 성향상 안맞다. 토스는 개발자, 기획자, 디자이너, 데이터.. 2023. 5. 21.
때 아닌 2022 개인 리뷰 개인 평가가 끝난 1월에 했어야 할 리뷰를 이제야 한다. 1월은 정말 바빴기 때문에 리뷰를 작성할 여유가 없었다. 물론 주말에 시간내서 할 수도 있었지만, 작년 1년을 돌아보면 힘들었던 기억들이 많이 떠올라서 리뷰를 작성할 마음이 안생겼다. 1월은 목표한 개발 할당량을 채우기 위해 전속력으로 달리고 있는 상태였기 때문에 나 스스로 긍정 마인드를 계속 주입해야만 했다(할 수 있다는 믿음, 해야만 한다는 각오 등). 그런 상태에서 힘든 기억을 끄집어내서 리뷰를 쓰려니 못하겠더라. 그래서 이번 리뷰는 건너뛸까 생각도 했지만, 지금이라도 기록해 놓으면 좋을거 같아서 작성한다. 2021년 5월에 투입되어 시작한 주문서 전환 프로젝트는 총 3개의 모듈로 나눠져있다. 1차, 2차, 3차에 걸쳐 순차적으로 전환할 예정.. 2023. 4. 30.
돈(Money) 타입 1. 돈(Money) 타입으로 BigDecimal 사용 주문서 프로젝트에서는 돈(Money) 과 관련된 필드를 BigDecimal 타입으로 통일시켰다. 실제론 정수값이라 해도 돈은 중요하니까 별도의 타입으로 표현하고자 하는 의도가 담겨 있다. 또한 예전에 라인 서비스와 연동할 때 환전과 관련된 스펙이 있었는데 기존에는 Long 타입으로 돈을 다루고 있다 보니 소수점 화폐를 처리하기 위한 수정 범위가 너무 커 진행하지 못한 히스토리도 있었다. 그래서 이후에라도 비슷한 요구가 왔을때를 대비해 BigDecimal 타입으로 하는게 좋겠다는 의견도 반영된거다. BigDecimal 타입으로 금액을 비교하고 계산하기 위해서는 유틸리티 클래스를 만들어 사용하는게 좋다. 아래 코드는 0.0 과 0 을 비교하는 로직이다... 2023. 4. 29.
DB mid 정리 logical data independence 에 대한 설명으로 적합하지 않는 것은? 1 1) Concerned with internal schema (v) 2) Concerned with conceptual schema 3) It is mainly concerned with the structure or changing the data definition 4) Modification at the logical levels is significant whenever the logical structures of the database are changed Conceptual schema 에 대한 설명으로 적절하지 않는 것은? 4 1) 전체적으로 통합된 데이터 구조이다. 2) 해당 기관이 필요로 하는 모든.. 2023. 4. 16.
EDA 에서 NullPointerException 조심하기 spring application 내부에서 메세지를 직접 주고받지 않고, event 기반으로 kafka 를 통해 메세지를 주고받는다면 NullPointerException 을 특히 신경써야한다. 아래 그림은, onStartOrder 에서 주문이 시작되서 포인트적립 Command message를 kafka 에 발행하고 onReservePoint 에서 포인트적립 Command message 를 받아서 처리하는 프로세스다. 포인트적립 Command message 에는 pointReserveDto 가 담겨있다. 스펙이 변경되서 새로운 필드가 필요해졌다. 그래서 newObject 를 만들어서 추가로 전달해주고, 포인트적립을 수행하는 onReservePoint 에서 get 해서 사용하게 수정하고 배포했다. 여기서 .. 2023. 4. 15.
java stream 으로 Map 다루는 방법 이전글 에서 java stream 으로 Grouping 하는 방법을 설명하면 중간에 map 을 이용하는 방법을 공유했다. 이 글에서는 다른 예제로 설명을 해보려고 한다. 먼저 product 와 item 구조는 아래와 같다. product 안에 item 들을 리스트로 가질 수 있다. @Value @Builder public class Product { long productId; List items; @Value @Builder public static class Item { long itemId; } } 외부 api 를 호출해서 여러개의 product 들을 가져온다고 해보자. 이때 item 을 다루기 위해선 이중 for 문이 필요하다. product 도 여러개인데 각 product 마다 item 들도 여.. 2023. 4. 6.
자기만의 트랙 예전에 인상깊게 읽었던 페북 글이 있었다. 회사 네임벨류가 내 실력이 아님을 꼬집는 글이었다. 나는 네이버라는 회사를 다닌다고 안주한적 없고 꾸준히 공부하며 나를 발전시켜왔다. 그럼에도 부족함을 계속 느껴 2년간 개인 수학과외도 받아보고, 새로운 팀으로 옮겨보는 등 다양한 경험들을 시도했다. 그래서 페북 글을 읽었을 때, 회사 간판에 취해있지 않았다는 자부심?은 있었다. 그러나 '나의 일을 나만의 언어로 설명' 할 수 있냐는 질문엔 자신있게 대답하지 못했다. 그래서 그때부터 더 열심히 회사에서 경험한 것들을 블로그에 정리하고 기록하고 있다. 정해진 기한을 맞추기 위해 빠르게 일을 쳐내다 보면, 전체를 보고 또 비즈니스 임팩트와 구조를 보면서 일하는것을 놓치기 쉽기 때문이다. 그리고 한번 정리한것으로 끝.. 2023. 3. 27.
DID 스터디 3회차(kotlin let/run/also/apply/with) DID 안드로이드 앱개발을 위해 kotlin 을 다시 공부하는 중이다. let 확장함수 코드를 보고 이전에 배웠던 let/run/apply/also/with 들을 다시 정리했다. 그전에 코틀린에서 많이 보이는 함수 패턴 중 하나를 간단히 살펴보자. 아래 func 함수는 두개의 인자를 받는다. 1. Int 타입의 age 2. Int 를 받아 Unit 을 리턴(Void 리턴) 하는 process(함수 타입) process 변수에 담길 함수는 전달받은 age 만 출력하는 단순한 로직이지만 확장성 있는 구조를 보여준다. preProcess 와 postProcess 를 계속 재활용하면서 process 부분만 새롭게 바꿀 수 있다. @Test fun test1() { // 코틀린에서 많이 보이는 패턴 func(34.. 2023. 3. 18.