본문 바로가기

전체264

왜 테스트 코드를 작성하는 걸까? 트레바리에서 혼자 3주라는 아주 짫은 시간에 구독 서비스을 만들었다. 낮밤, 주중/주말을 가리지 않고 정해진 기한 내에 개발을 마치고 싶었다. 여유 없이 기한내에 개발을 하다보니, 스스로 끊임없이 일정을 핑계삼아 올바른 길보다는 빠른 길을 찾으려는 타협점을 끊임없이 찾으려 했다. 트레바리의 개발 문화는 테스트 주도 개발 이라는 (사실 거창한건 아니지만) 문화을 CTO님이 최우선을 둔다. 나 또한 CTO 님의 영향 덕택에 테스트 코드을 마치 습관처럼 작성한다. 테스트 코드의 장점은 CTO 님 덕택에 직접 몸소 느끼고 있다. (장점에 대해서 중심으로 이야기하지는 않을 예정이다.) 구독 서비스을 만들면서 빠른 길을 찾기 위해서 습관처럼 작성하던 테스트 코드을 중간부터는 스킵하고 넘어가기 일쑤였다. 그러다 보니.. 2022. 10. 29.
DB AutoIncrement 가 아니라, 왜 굳이 IDGenerator Server 을 만들었을까? 추가) 관련 IDGenerator 오픈소스을 만들었습니다. ( github link ) 배경 @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; } 위 코드는 어떤 코드인지 짐작이 가는가? JPA 을 학습한 사람이라면 한번에 인지했을 것이다. 데이터베이스에 어떤 데이터을 저장시키기 위해서 데이터베이스에게 오름차순의 숫자을 요청하여 식별자 을 생성해내는 코드이다. 포스팅 제목에서 보았던 IDGenerator 종류의 하나이다. 이 쯤에서 제목에서 말하는 IDGenerator 는 무엇인지 이해할 필요가 있다. 앞에서 이미 언급된 '식별자' 을 만들어 주는 것이 IDGenerator 의 역할.. 2022. 10. 5.
Mockito을 왜 쓰는지 모르겠다? (with. Test Double) 안녕하세요. 렌입니다. 오늘은 우리가 테스트 코드 작성할 때마다 Mockito 을 사용하는데, 왜 사용하는지 대해서 조금 더 깊게 이야기해볼까 합니다. 테스트하고자 하는 객체의 의존성을 격리한다. 라는 것이 우리가 흔히 아는 왜 사용하는지에 대한 답인데요. 여기서 Mocktio 는 Test Double 라는 큰 개념 안에 있는 하나입니다. Test Double에 대해서 알게 된다면 Mocktio 을 왜 사용하는지 조금은 이해할 수 있지 않을까요? When we are writing a test in which we cannot (or chose not to) use a real depended-on component (DOC), we can replace it with a Test Double. The .. 2022. 9. 22.
좋은 테스트에 대해서 이야기 하기 좋은 테스트에 대해서 이야기해볼까 합니다. 여기서 '좋은' 이라는 말은 개발자에게 언제나 고민의 시작이지 않았을까 싶습니다. 직접 테스트 코드를 작성하며 이 책(이펙티브 유닛 테스팅)에서 말하는 좋은 테스트에 대해서 공감이 되는 부분이 몃년이 지나서야 드디어 조금씩 알게되는 것 같습니다. 다음과 같은 주제로 이야기해보려 합니다. _2.1 읽기 쉬운 코드가 유지보수도 쉽다. _2.2 구조화가 잘 되어 있다면 이해하기 쉽다 _2.3 엉뚱한 걸 검사하는 건 좋지 않다 _2.4 독립적인 테스트는 혼자서도 잘 실행된다 읽기 쉬운 코드가 유지보수도 쉽다. 여기서 말하는 읽기 쉬운 코드란 어떤 코드를 말하는 걸까요? 그 가독성은 어떻게 채울 수 있을까요? 가독성 높은 코드? 가독성 이라는 단어는 눈으로는 이해할 수 .. 2022. 9. 18.
postgresSQL의 Idle in transaction 이란 무엇인가? Node.js 에서 발생한 Transaction 이 부족해서 문제가 발생했고, 해결하는 과정에서 Idle in transaction에 대해서 알게 되었습니다. Idle in transaction 이란 무엇인가? 문서에 따르면 다음과 같은 의미를 가집니다. idle in transaction (waiting for client inside a BEGIN block) 클라이언트가 시작을 열어놓고 기다리고 있다. 즉, 클라이언트가 정상적으로 트랜잭션을 닫지 않았다. 대부분의 Application은 ConnectionPool 을 통해 N개의 Connection 을 쥐고 있습니다. N개의 Connection이 모두다 정상적으로 동작하지 않을 경우에는 다음 Connection 이 열리지 않아 문제가 발생합니다. 그.. 2022. 9. 11.
ConnectionAcquireTimeoutError [SequelizeConnectionAcquireTimeoutError] 문제 해결하기 운영중에 Node.js 모듈이 간혈적으로 갑자기 기능이 동작되지 않는 이슈가 있었습니다. 가장 처음에는 트랜잭션 자체가 동작되지 않아, 로그를 살펴보니 위와같은 내용이 있었습니다. 이게 왜 발생했을까요? Node.js 에서 ConnectionAcquireTimeoutError 이 발생했는데, 이유를 알 수 없었습니다. 에러 메세지에 대한 원인을 찾아보니, Transaction 이 ConnectionPool 을 물고 있고, graphql에서 새롭게 만들 트랜잭션이 없어서 발생한 문제점이라는 사실을 알았습니다. 최근에 const transaction = await sequelize.transaction(); 관련된 작업이 있었고, 그곳에서 transaction 이 정상적으로 종료되지 않았음을 알 수 눈치챌 .. 2022. 9. 11.
엄청 많은 속성을 가진 객체를 테스트해야 한다면 어떻게 해야될까?(with. test Data Builder) SETTLEMENT 라는 결제/환불 원장 프로젝트를 진행하면서 이야기했던 Test Data Builder 에 대해서 이야기해볼까 한다. Test Data Builder(테스트 데이터 빌더)란 어떤 건인가? 테스트 데이터 빌더를 이야기하기 전에 테스트 코드부터 이야기 해보자. 왜 테스트 코드를 작성하고자 할까? 왜 테스트 코드를 작성하고자 할까? 우리는 테스트 코드로서 무엇을 얻기 위해서일까? 어떤 문맥이냐?에 따라 테스트 코드가 우리에게 전달해주는 것은 다를테지만, 이야기하고 싶은 바를 먼저 말한다면- 안도감이다. 테스트 코드 덕분에 마음의 안정을 얻을 수 있다. 그것은 서비스를 개발하는 클라이언트에게 심리적인 안정감을 준다. '그럼 무조건 테스트 코드를 작성해야 되는거 아닌가?' 라는 생각이 드는 사람.. 2022. 9. 9.
대체 application.properties 는 어떻게 동작되는 거지? [요약] 1. application.properties 가 인식되는 코드가 변경되었다. 2. config 의 위치에 따른 우선순위 순서가 있다. 3. springboot 는 default 가 .properties 이고, .yml 을 인식하기 위해서는 EnvironmentPostProcessor 를 알아야 한다. 의식의 흐름대로 어떻게 application.properties 를 스프링 부트가 이해할 수 있는지 알아보자. 어느 시점부터 동작 방식이 변경되었다. Spring 2.4.0 부터 application.properties 를 인식하는 것이 스프링부트 코드 내에서 변경되었음을 코드를 통해 확인할 수 있었다. 이전에는 ConfigFileApplicationListener 를 통해서 application.. 2022. 9. 3.
야놀자 이준영님, 한기영님과 이야기하며 느낀점 두 분다 실제로 뵌 적은 사실 단 한번도 없습니다. 오직 동영상 속에서만 대화했습니다.(당연히.. 속으로요.) 우연인지, 필연인지 알 수 없지만 이준영님의 Wanted 동영상과 유튜브 채널의 EO 에서 한기영님 관련 동영상을 볼 수 있었습니다. 이준영님의 Wanted 동영상 40대 중반이 돼서야 깨닫고 실천할 수 있게 된 것 - 한기용 1부 이 두 개의 동영상을 보면서 많은 생각을 하게 되더라구요. 비슷한 커리어를 가지셨고, 인생 전반에 대한 진솔한 성찰 듣고 있노라면, 대기업에서 작은 스타트업으로 오면서 했던 저의 고민이 비슷하게 겹쳤습니다. 제가 겪었던 고민과 이준영님과 한기용님 동영상에서 이야기하고 싶은 내용을 비교하며 이야기 하고 싶었습니다. 두 분다 산전수전 많은 경험을 했습니다. 그 산전수전의.. 2022. 7. 24.
안전하게 코드 리팩토링하기 - 1 안전하게 리팩토링하기 SOLID 원칙 중 DIP가 있다. 어떻게 하면 쉽게 리팩토링 할 수 있는지 간단하면서도 강력한 방법을 이야기해볼까 한다. 이것을 아래와 같이 변경한다고 해보자. public class LotteriesFactory { private final RandomNumberGenerator randomNumberGenerator; public LotteriesFactory(RandomNumberGenerator randomNumberGenerator) { this.randomNumberGenerator = randomNumberGenerator; } // 만약 많은 곳에서 해당 코드를 사용하고 있다면 어찌하겠는가 ???????? public String createNumber(){ retu.. 2022. 7. 24.
적절한 마이크로서비스를 도입하는 시기는 언제일까? 지난 해 9월 트레바리 테크유닛으로 이직을 결정하게 된 주요 이유 중 하나는 마이크로서비스를 직접 구축 할 수 있는 기회에 있었습니다.. 이 후 약 8개월이 지난 이 시점에 '적절한 마이크로서비스를 도입하는 시기는 언제 일까?' 을 고민하는 것은 뒷북일 수 있지만, 이제는 이 부분에 대해서 어느정도 답을 할 수 있는 시점이 아닐까? 싶어 고민하게 되었습니다. 1. 다우기술에 근무할 적 약 90만 라인이 자바 코드가 모듈형 모놀리스 아키텍쳐로서 운영되는 프로젝트를 약 2년 넘게 관리했었습니다. 이 방대한 코드 속에서 마이크로서비스가 말하는 모놀리스 아키텍쳐의 단점을 운이 좋게도 모두다 겪어볼 수 있었습니다. 약 2주에 한 번씩 배포 빈도를 가집니다. 코드가 심각하게 방대해, 도메인에 집중할 수 없어 스파게.. 2022. 7. 9.
이벤트 스토어(?) 이벤트 소싱(?) 를 활용한 View 를 반복적으로 만들고 부수면서 느낀 점 결론부터 말씀드리면 '이벤트스토어를 활용해 내가 원하는 View 를 만들어 내기란 여전히 턱없이 내공이 부족하다.' 입니다. 먼저 이벤트스토어에 대한 이야기부터 해보려 합니다. 그 다음 반복적으로 만들고 부수면서 느낀 점 이야기 해볼까 합니다. 이벤트 스토어란 무엇일까? 이벤트 스토어가 없던 시절의 우리는 데이터베이스에 어떤 행위의 결과값만 포함시켜왔습니다. Actor에 의해 만들어진 어떤 결과물을 의미합니다. 그렇다면 이벤트란 무엇일까요? 사내에서 이벤트라는 용어를 비개발자분들에게 설명하기 위해 사용된 장표를 가져왔습니다. 이벤트는 특정시점에 발생한 어떤 사건을 의미합니다. 그러므로, 이벤트 스토어는 특정시점에 발생한 사건을 저장하는 것을 의미합니다. 이것이 가져다는 주는 이점은 무엇일까요? 1. 바로.. 2022. 7. 3.
Message Relay 를 PollingPublisher 방식으로 구현하기 이벤트 소싱을 하기 위해서는 트랜잭션 아웃박스 패턴을 구현해야 합니다. 당연히 트랜잭션 아웃박스 패턴에 대한 이해가 있어야 합니다. 다만, 해당 포스트에서는 자세한 트랜잭션 아웃박스 패턴을 다루지 않을 계획입니다. 다시 트랜잭션 아웃박스 패턴를 표현하는 위 그림에서 네모난 부분이 바로 메세지릴레이를 수행하는 곳입니다. 데이터베이스에 특정 데이터가 Insert 되면, 변경분에 대해서 MessageRelay 는 특정 데이터를 읽어 Message Broker 에게 전달한다. 이 때 MessageRelay 의 구현방식은 2가지가 있습니다. 1. Polling publisher 2. Transaction log tailing 1. Polling publisher 는 일정 주기마다 변경분을 조회해서 메세지를 전달하.. 2022. 6. 19.
패턴, 가치, 원칙에 대해서 켄트백의 구현패턴 책에서 나오는 내용을 읽으며, 일부 발췌한 내용이 포함됩니다. 프로그래밍은 무엇일까? 왜 개발을 하는 걸까? 분명 처음에는 어떤 성취감에 의해서 분명 접근했었지만, 약 3년이 지난 시점에서 나에게 개발을 하는 이유를 묻는 다면 커뮤니케이션을 잘하기 위해서, 라는 말이 먼저 나오는 것 같다. 그렇다면 (개발 > 커뮤니케이션) 일까? 개발은 생업으로 하다보니 (과거 토이프로젝트 하던 때와는 달리) 내가 혼자 할 수 있는 것은 거의 없더라. 누군가와 협업을 해야만하고 기한내 목표를 달성하는 것 만이 유일한 목표가 되곤한다. '켄트백의 구현패턴' 책은 이런 부분을 마치 처음부터 알고 있듯이 이야기한다. 결국 이 책 전체는 커뮤니케이션을 돕는 프로그래밍 기법에 초점을 두고 있다. 코드를 통한 커.. 2022. 6. 13.
정규표현식에서 알지 못했던 capture group 과 non- capture group val groupMD = """((?:\+|\+-)?[.\d]+)([*/])((?:\+|\+-)?[.\d]+)""".toRegex() fun foldGroup(v: String): Double = groupMD.findAll(v).fold(0.0) { acc, curr -> val (_, left, op, right) = curr.groupValues val leftValue = left.replace("+", "").toDouble() val rightValue = right.replace("+", "").toDouble() val result = when (op) { "*" -> leftValue * rightValue "/" -> leftValue / rightValue else -> throw T.. 2022. 6. 6.
REST API 에서 URL은 무슨 의미인지 살짝 맛 본 썰!! 이번에 멤버십 환불/해지 고도화 프로젝트를 하면서 API 에 대한 피드백이 있었습니다. 아래 "/v1/membership" 에 대한 API 는 무엇을 의미하는 걸까요? 잠시 숨을 고르고 천천히 코드를 살펴봅니다. @GetMapping(value = {"/v1/membership"}) public String member(@RequestParam(value = "clubId") String clubId, @RequestParam(value = "userId") String userId, @RequestParam(value = "state") String state) { Member member = membershipGetUseCase.member(UserId.of(userId), ClubId.of(club.. 2022. 5. 19.
'멤버십 환불/해지' 프로젝트를 마치며. '멤버십 해지/환불' 고도화 프로젝트를 마치며 [TOC] 이 포스트를 통해 무엇을 말하고 싶은지? 왜 이것을 하게 되었는가? 스스로 생각하길 잘하지 못한 부분 스스로 생각하길 잘한 부분 왜 이것을 하게 되었는가? 트레바리는 오프라인 서비스이다. 대다수의 많은 유저는 약 4번의 오프라인 서비스 이용을 위해 20만원 이상의 금액을 낸다. 20만원 이상의 금액을 사용하는 하는 유저에게는 클럽에 참여할 수 있는 권한. 즉 멤버십 이 생겨난다. 만약, 해당 유저가 '더 이상 모임에 참여를 원하지 않는 경우에는?' 어떻게 되는가? 유저에게는 모임에 참여할 수 없도록 멤버십이 해지되고, 결제한 금액에서 수수료를 제외한 일부 금액을 환불받게 된다. 대부분이 '더 이상 모임에 참여를 원하지 않는 경우' 에 멤버십 해지와.. 2022. 5. 16.
헥사고날 아키텍처(Hexagonal Architecture) 코드로 이해 해보기 EventsJdbcEntityRecordPublishedEventService 이 부분은 '만들면서 배우는 클린 아키텍쳐' 의 책을 보고 배운점과 느낌점을 설명합니다. 헥사고날 아키텍쳐란 무엇인까요? 헥사고날 아키텍쳐는 레이어드 아키텍처(Layered Architecture)의 단점을 해결하기 위해 나왔습니다. 어떻게 해결했는가? 바로 의존성의 역전법칙입니다. 우리가 흔히 아는 레이어드 아키텍쳐는 위에서 아래로 의존성을 가진 형태를 의미합니다. 여기서 만약 의존성 역전 법칙을 활용하면 아래와 같은 아키텍쳐로 변경되어집니다. 이런 형태를 각 계층마다 적용하다 보니, 핵사고날 아키텍쳐의 형태를 띄게 됩니다. 육각형 안에는 도메인 엔티티와 상호작용하는 유즈케이스가 있고, 모든 의존성을 엔티티를 향해 있습니다... 2022. 4. 29.
Springboot 에서 react.js 연동시 모든 view 맵핑을 index.html으로 forwarding 하는 방법은? [문제] SpringBoot 에서 thymeleaf 대신, React.js 를 ViewTemplate 로 사용하려 한다. 기존의 thymeleaf 는 html 별로 View을 맵핑하고 있었기 때문에, 하나의 html 에서 URL에 따른 여러 화면으로 라우팅되는 SPA Application 에서는 ViewName 맵핑이 정상적으로 동작되지 않는다. ( 참고자료 ) 예를 들어, product/list 라는 View 이름으로 맵핑을 시도한다고 가정해본다면, 프로젝트에서는 /WEB-INF/templates/product/list.html 와 같은 형태로 ViewTemplate 을 맵핑하기 위한 html 이 존재해야 합니다.(꼭, html 일 필요는 없음) 그러므로, 하나의 html 에서 원하는 URL로 라우팅시.. 2022. 4. 26.
Postgresql 에서 epoch time 을 읽을 수 있는 timestamp 변환하는 방법은? 우리가 다루는 시간 중에는 epochtime 이라는게 존재합니다. // epochtime 1970년 1월 1일 00:00:00 UTC 부터 지금까지의 경과 시간을 초로 환산하여 정수로 나타낸 것을 말한다. DB 를 다루다보면, Application 에서 DB 에 데이터를 삽입할 때, application의 date 타입을 Timestamp 로 변환해서 넣는 것이 문제가 되는 경우가 더러 있습니다. 한번만 사용되어지는 DB 라면 더욱더 해당되는데, 종종 ViewTable을 만들기 위한 용도로 만들 경우 약간의 트릭으로 Timestamp 에 넣어야 할 값을 Bigint 타입으로 CREATE Table 한 뒤, 어플리케이션에서 epochtime 으로 값을 삽입합니다. 아래 epochtime 으로 값을 넣을 경.. 2022. 4. 26.