묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결장애를 허용하는 견고한 시스템 만들기
안녕하세요 주문처리에 관하여 질문있습니다 ㅠ ㅁ ㅜ
안녕하세요. 주문 처리에 관련해서 질문 있습니다!!고민하다가 질문드려요 ㅠ!중복 주문을 해결하기 위해 주문 생성 API , 주문 처리 API를 나누는걸로 이해하고 있습니다.만약 쇼핑몰에서 사용자가 주문을 할때 주문 생성 API를 요청하고 결제처리 (PG사) 성공하면 주문 처리 API(재고차감 등등) 를 하는걸로 알고 있습니다.하지만 주문 생성 API에서 수량을 검증한다고 하더라도 결제를 완료하고 주문 처리를 할때 다른 사용자에 의해서 재고가 부족할수 있는 상황이 있다고 생각합니다.이럴때는 실무에서 어떻게 해결하는지가 궁금합니다!!!!비동기적으로 보상해준다고 하면 뭔가 사용자입장에서 결제까지 했는데 재고가 부족해서 주문처리가 실패하여 환불까지된다?.... 이게 좀 비효율적이라 생각해서요!!답변 부탁드립니당실무에서는 어떻게 사용하나요 ! 궁금해요ㅠㅁㅠ
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
TransactionManager 분리
TransactionManager 분리에 대해서 이해가 잘 가지 않는게 있어. 실제 운영 환경에서는 배치와 비즈니스 데이터 DB를 분리하는게 필수라고 했잖아?근데 이 분리의 단위가 배치용 메타데이터 저장만 분리를 하는게 맞는거야? 현재 사이드 프로젝트에서 멀티모듈 구조에 (MSA는 아님) API 모듈과 배치 모듈을 따로 분리한 상태야.유저 데이터에서 생일을 뽑아서 내일 생일인 유저에게 FCM 을 발송하는 배치를 만드는데,이때 만들어준 예제처럼 @BatchDataSource와 비즈니스 로직용 @Primary DataSource를 분리하게 되면,API 모듈용 DB Connnection을 배치에서도 똑같이 갖다 쓰는거 아니야 ?? 즉, 배치에서 API 쪽 커넥션을 가져다 써서 배치가 돌 때 커넥션이 고갈날 수 있지 않을까? 라는 생각이 들었어지금 이해한 바로는 @BatchDataSource, @BatchTransactionManager를 분리하고 주입해줘도 Reader -> Processor -> Writer 에는 @Primary 걸 쓰는것 같은데 맞아 ?나는 DB 분리와 함께, 비즈니스 로직에 대한 커넥션, 트랜잭션도 배치용으로 분리하고 싶은데 이럴땐 어떻게 해야해?특히나 배치에서도 JpaTransactionManager를 쓰고 싶은 경우에는 어떻게 해야해 ?원하는 바는, API 처리용 DB 커넥션은 커넥션대로 있고, 배치 메타데이터용 커넥션 따로, 배치에서 라이브 DB에서 유저 데이터를 가져오는 커넥션 따로 구성하고 싶어 (배치가 API 모듈 에 영향을 주지 않았으면 해서,,,) 혹시 내가 강의를 제대로 이해를 못한거라면 알려줘
-
미해결개발자에게 필요한 로그 관리
kibana > dicover 화면이 다르게 나와요
http://localhost:5601/app/discover#/ 진입하면 현재 이렇게 나옵니다. 저기서 add integration 누르면 다음 화면처럼 나오는데.. 진행을 어떻게 해야될지 모르겠습니다.
-
미해결웹소켓/STOMP 채팅서비스(spring, vue, redis)
메시지 브로커 선택에 관한 질문
안녕하세요, 강의에서는 메시지 브로커용으로 redis를 사용하셨는데, redis 외에도 rabbitmq나 카프카 같은 것들도 사용되는 것으로 알고있습니다. 그 중에서 특별히 redis를 사용한 이유가 있는지 궁금합니다.그리고 무중단 배포 시 스프링 내장 브로커를 사용하면 서버 재실행 시 구독 정보가 초기화되기에 메시지 브로커를 도입하려고 하는데 이때는 셋 중에 어떤 것을 사용하면 좋을지 궁금합니다.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
오타(?) 발견
킬구형 강의 자료 중간에 이상한 문구 발견해서 제보해강의 회차: 5장. 작전4: Flow - 배치의 흐름을 지배하라 (분기점에서 생사를 쥐락펴락하라 ☠🏴☠)이상한 문장: 즉, Spring Batch의 암시적 전환 규칙 대상에서 제외된다는 뜻이다.재시도Claude는 실수를 할 수 있습니다. 응답을 반드시 다시 확인해 주세요.강의 자료 중간에 LLM에서 가져온 내용을 잘못 편집한 것 같아.
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
코틀린에서 value class 적용 시 문제
안녕하세요 코틀린으로 현재 강의를 수강하고 있는 수강생입니다. 현재 자바로 작성된 코드를 보고 설명과 함께 어떤 이유로 이런 코드를 작성한 것인지 생각하며, 코틀린으로 이 개념을 적용하면 어떻게 작성할 수 있을지 DDD와 클린 아키텍처를 코틀린 문법 활용하여 구상하는 연습 중입니다. 현재 Member 도메인 코드 개선 강의에서 value class 적용하여 필드의 값이 바뀌는 문제(email자리에 nickname이 오더라도 같은 String이라 컴파일 에러가 안 남)를 해결하려 시도했습니다 package org.example.splearn.domain @JvmInline value class Email( val value: String, ) @JvmInline value class Nickname( val value: String, ) @JvmInline value class PasswordHash( val value: String, ) class Member private constructor( val email: Email, var nickname: Nickname, var passwordHash: PasswordHash, var status: MemberStatus, ) { fun activate() { check(status == MemberStatus.PENDING) { "회원이 PENDING 상태가 아닙니다" } this.status = MemberStatus.ACTIVATE } fun deactivate() { check(status == MemberStatus.ACTIVATE) { "회원이 ACTIVE 상태가 아닙니다" } this.status = MemberStatus.DEACTIVATED } fun verifyPassword( password: String, passwordEncoder: PasswordEncoder, ): Boolean = passwordEncoder.matches(password, this.passwordHash.value) fun changeNickname(nickname: String) { this.nickname = Nickname(nickname) } fun changePassword( password: String, passwordEncoder: PasswordEncoder, ) { this.passwordHash = PasswordHash(passwordEncoder.encode(password)) } fun isActive(): Boolean = this.status == MemberStatus.ACTIVATE companion object { fun create( memberCreateRequest: MemberCreateRequest, passwordEncoder: PasswordEncoder, ): Member = Member( email = memberCreateRequest.email, nickname = memberCreateRequest.nickname, passwordHash = PasswordHash( passwordEncoder.encode(memberCreateRequest.password.value), ), status = MemberStatus.PENDING, ) } } 강의대에서는 static 메소드인 of에서 MemberCreateRequest를 파라미터로 사옹하고 있습니다. 코틀린이라 companion object를 사용했구요 그러던 중 "헥사고날 아키텍처의 특성을 고려하면 의존성 외부 로직인 dto가 내부로 향해야 하고 따라서 도메인이 dto에 의존하는 것이 괜찮을까" 하는 의문이 들었습니다. companion object { fun create( email: Email, nickname: Nickname, password: String, passwordEncoder: PasswordEncoder, ): Member = Member( email = email, nickname = nickname, passwordHash = PasswordHash( passwordEncoder.encode(password), ), status = MemberStatus.PENDING, ) }그래서 코드를 수정해 보면 이런 식으로 수정해 볼 수 있을 것 같습니다. 이에 대해서 토비님 의견이 어떠신지 여쭙고 싶습니다
-
해결됨백엔드 개발자 성능 개선 초석 다지기
thread pool
common pool을 사용하지 않도록 thread pool을 설정 해야 된다고 주의사항을 적어주셨는데 그 이유는 무엇인가요?그리고 둘의 차이는 onPool-worker-3, pool-1-thread-8 이라고 알려주셨는데 차이가 이거밖에 없는건가요?
-
미해결Spring Boot TDD - 입문부터 실전까지 정확하게
아키텍처와 TDD의 오해에 대해 질문드립니다.
안녕하세요, 강사님! Spring Boot TDD 강의 정말 잘 듣고 있습니다. 강의 내용 중 궁금한 점이 생겨 질문드립니다.보통 Spring에서 개발할 때 Controller-Service-Repository 구조의 레이어드 아키텍처를 많이 사용하는데요, 강의에서는 컨트롤러가 직접 리포지토리의 save 같은 메서드를 호출하면서 비즈니스 로직을 처리하는 경우가 있는 것 같습니다.혹시 이것이 강의의 핵심 내용에 집중하기 위해 코드를 단순화하신 것인지, 아니면 강사님께서 실제로 선호하시는 개발 스타일이신지 궁금합니다. 만약 후자라면 어떤 장점이 있는지 그 이유에 대한 의견을 여쭙고 싶습니다.더불어, "TDD를 잘하려면 인터페이스를 많이 사용해야 한다"는 것이 일종의 오해라는 말씀에 크게 공감했습니다. 그런데 왜 개발자들 사이에서 이런 오해가 생겨나게 된 것인지 그 배경이 궁금합니다.마지막으로 추후에 비즈니스가 복잡해지면 테스트가 깨졌을 때 어디가 문제인지 파악이 어려울 것 같은데요 이에 따른 문제를 어떻게 해결하시나요? 단위테스트를 추가로 작성하시는지도 궁금합니다.
-
미해결웹소켓/STOMP 채팅서비스(spring, vue, redis)
WebSocket과 Spring Security 질문
WebSocket 연결이 처음 http요청으로 시작하기 때문에 필터 체인이 요청을 가로챈다.따라서 /connect를 permitAll()로 풀어줘야 400에러가 안난다. 로 이해했는데 맞을까요?
-
미해결Spring Boot TDD - 입문부터 실전까지 정확하게
임의데이터 generator방식과 @Transactional에 대한 고찰
안녕하세요, 강사님. TDD 관련 강의 항상 잘 듣고 있습니다.강의 내용을 따라 실습을 진행하던 중, 테스트 격리 전략에 대해 궁금한 점이 생겨 질문 남깁니다. # 강의에서 다뤄주신 상황강의에서처럼 여러 테스트 메서드에서 동일한 이메일 값을 사용하니, 테스트 클래스 전체를 실행했을 때 JPA의 유니크 제약 조건 위반 에러가 발생했습니다. 이로 인해 개별 테스트는 성공하지만 전체 테스트는 실패하는 상황에서 궁금증이 생겼습니다. # 제가 먼저 생각한 해결책: @Transactional을 이용한 롤백저는 강의를 들여면서 이 문제를 해결하기 위해, 각 테스트 메서드에 @Transactional 애너테이션을 붙여 테스트가 끝나면 자동으로 롤백시키는 방식을 먼저 떠올렸습니다. 이 방법으로 각 테스트가 독립적인 트랜잭션 내에서 실행되고, DB 상태를 다음 테스트에 영향을 주지 않는 상태로 유지할 수 있다고 생각했습니다. ##강사님의 방식(임의 데이터 generator)에 대한 질문##그런데 강사님께서는 강의에서 롤백 방식을 사용하지 않으시고, UUID 등을 활용해 매번 고유한 이메일 주소를 생성해주는 데이터 제너레이터 방식을 사용하셨습니다. 강의에서도@Transactional 을 성능 등 여러가지 이유로 인해 사용하지 않았다고 하셨는데요.@Transactional을 이용한 롤백 방식도 충분히 좋은 해결책이라고 생각했는데, 강사님께서 UUID 생성 방식을 선택하신 특별한 이유나 설계 철학이 궁금합니다.혹시 제가 생각한 롤백 방식에 비해 UUID 생성 방식이 갖는 실용적인 장점(ex. 롤백을 하지 않으니 디버깅의 용이성(?))이 있을까요? 두 방식의 장단점과 어떤 상황에서 어떤 전략을 선택하는 것이 실무에서 더 좋을지에 대한 강사님의 고견을 듣고 싶습니다. 감사합니다!
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
오타 발견
가령 다음과 같이 getExecutionContextSerializer() 메서드를 오버라이드하면g에 볼드처리안됨--원시적 침투 예제의 BatchConfig에서 DefaultBatchConfiguration 상속을 제거하고@EnableBatchProcessing을 추가하자. 다음과 같이 말이다.예제밑의 예제가 그냥 기존 DefaultBatchConfiguration 방식만 나와있음아마 기존과 수정을 두개 다 표시하는식으로 하고싶었을거같음--JobContext/StepContext: Late-Binding의 최종 무기고키룩형 JobContext/StepContext가 존재하면 배치 스코프가 활성화된 상태라는 것은 알겠어. 근데 이 JobContext/StepSontext 대체 어디에 써먹는거지? 단순히 활성화를 의미하는게전부인가?키룩형 -> 갈매기가 되고싶은 내면의 소리일수있음괜찮음 주변에 돌멩이 지망생도 있고 독수리 지망생,딸기우유 지망생도 있어서 이해할수있음
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
안녕하세요 코틀린으로 강의 수강 시 도메인 코드 질문드립니다
좋은 추석 보내고 계신가요?현재 코틀린으로 강의를 따라해 보고 있습니다. class Member private constructor( val email: String, var nickname: String, var passwordHash: String, var status: MemberStatus, ) { fun activate() { check(status == MemberStatus.PENDING) { "회원이 PENDING 상태가 아닙니다" } this.status = MemberStatus.ACTIVATE } fun deactivate() { check(status == MemberStatus.ACTIVATE) { "회원이 ACTIVE 상태가 아닙니다" } this.status = MemberStatus.DEACTIVATED } fun verifyPassword( password: String, passwordEncoder: PasswordEncoder, ): Boolean = passwordEncoder.matches(password, this.passwordHash) fun changeNickname(nickname: String) { this.nickname = nickname } fun changePassword(password: String) { this.passwordHash = password } companion object { fun create( email: String, nickname: String, password: String, passwordEncoder: PasswordEncoder, ): Member = Member( email, nickname, passwordEncoder.encode(password), MemberStatus.PENDING, ) } }이러한 식으로 작성하였는데 자바에서는 const로 선언한 객체나 변수가 아닌 이상 기본적으로 가변입니다. 그런데 코틀린에서는 val, var 키워드에 따라서 var로 선언해야 가변 타입이 됩니다. Member 도메인 모델 확장 챕터 수강하고 있는데 이 경우는 도메인에서 가변 속성을 미리 정의하고 해당 속성들을 var로 선언하는 것이 맞을지, 혹은 val을 통해 불변성을 확보하고 새 객체를 생성하여 변경을 처리하는 것이 적합할지 궁금합니다.코틀린에서 도메인 코드를 작성할 때 자바와 다른 문법&개념과 도메인 중심 설계가 종종 난해할 때가 있네요.
-
미해결Spring Boot TDD - 입문부터 실전까지 정확하게
내부 설계에 의존하는 테스트 관련 질문 드립니다.
강의를 들으면서 내부 설계에 의존하는 테스트라는 것이 무엇인지 조금 헷갈려서 질문 드립니다. 강의 초반에는 테스트가 내부 설계에 의존해서는 안된다고 말씀 주셨습니다. 내부 설계에 의존하게 되면 테스트가 깨지는 등의 부작용이 발생할 수 있기 때문이라는 점도 함께 말씀 주셨는데, 이번 강의에서는 내부 설계에 의존해야 하는 케이스를 설명 해주셨습니다. 다만 왜 이런 케이스에는 내부 설계에 의존해야 하는지를 확실하게 이해를 하지 못했습니다. 조금 더 자세한 질문을 드리자면내부 설계의 의미내부 설계에 의존해야 하는 이유이 두가지를 잘 이해하지 못한 것 같습니다.내부 설계라는 것이 클라이언트가 실제로 사용하는, 외부로 공개된 인터페이스를 제외한 모든 부분을 말하는 것일까요? 이번 강의에서 내부 설계에 의존해야 하는 이유는클라이언트는 어떤 방식으로 암호화를 하는지 알 필요가 없다.하지만 현재 공개된 인터페이스로는 실제 비밀번호가 평문으로 저장이 되었는지, 아니면 정말 암호화가 이루어져 저징이 되었는지를 확인할 수 있는 방법이 없다.그러므로 실제 암호화 로직을 테스트 해야한다 (내부 설계에 의존해야 한다)정도로 이해했습니다만 제가 맞게 이해한 것인지 감이 오질 않습니다. 요약하자면내부 설계란 외부로 드러난 인터페이스 외적인 것들을 말하는 것인지왜 내부 설계를 의존해야만 하는 상황이 발생하는지정도일 것 같습니다. 감사합니다.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
멀티모듈에서 DB 커넥션 풀 분리
DataSource에 대한 질문 배치를 적용중인데, 멀티모듈에서 배치용 Application을 따로두고, 배치용 yaml에서 datasource를 두었고, api쪽도 yaml에서 datasource를 보고 있다.이때 , 아래와 같이 Config에서 Bean을 통해 Datasource을 생성, JobRepository에 전달해주지 "않아도" 커넥션이 분리가 되는가?API 쪽 디비와, 배치 디비의 커넥션풀을 따로 쓰고싶은데 아래와 같이 별도 세팅 없이 yaml만으로 분리는 안되는지 궁금하다...@Configuration class JpaConfig { @Bean @ConfigurationProperties("spring.datasource") fun batchDataSource(): DataSource { return HikariDataSource() } @Bean fun jobRepository( batchDataSource: DataSource, transactionManager: PlatformTransactionManager, ): JobRepository { return JobRepositoryFactoryBean().apply { setDataSource(batchDataSource) setDatabaseType(DatabaseType.POSTGRES.name) setTransactionManager(transactionManager) afterPropertiesSet() }object } }
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
스프링 DB연결
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 자바부터 강의를 듣고있는데 언어가 이해가 되는부분이 있고 안되는 부분이있는데 이거는 앞에가서 다시 학습을 하고와야하나요!?지금 스프링입문은 여기서 다이해하고 다음 강의로 넘어가야 하는 건가요!?
-
해결됨스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
*가 아니가 article_id로 count를 뽑아줘야 할까요?
@Query( value ="select count(t.article_id) from ( " + " select article_id from article where board_id = :boardId " + "limit :limit " + ") t", nativeQuery = true ) Long count(@Param("boardId") Long boardId, @Param("limit") Long limit);위와 같이count(*)가 아니라 count(t.article_id) 처럼 alias도 붙여야 하고, 모든 걸 뽑는 게 아니라 딱 서브쿼리 안에서 추출한 article_id만 count로 뽑아줘야 테스트가 통과되더라고요.이유가 있을까요...?
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
오타 발견
SimpleStepHandler - Step 실행의 관리자Step의 실행은 StepHandler에 의해 의해 통제된다. Spring Batch는 기본 구현체로 SimpleStepHandler를 사용하는데, 이 컴포넌트가 Step 실행의 전체 라이프사이클을 관리한다.의해 의해 <-그리고 Step Squad 핵심 요약 있으니까 너무좋은데 Job Squad 에서도 핵심요약이 있었으면 더 좋았을거같음뭐 스탭이나 잡이나 내용이 거의 비슷비슷하긴한데(Execution 반드시 새거만들고,상태변경시 즉시 메타데이터저장소에 저장하고)그래도 실제 실행 따라가는 느낌이라 정리가 잘 안되는느낌이긴해서 마지막에 방점찍으면 보기 더 편할거같은느낌
-
해결됨Spring Boot TDD - 입문부터 실전까지 정확하게
테스트 시나리오 관련 질문 드립니다.
테스트와 코드간 성장 헙력 관계를 보면서 문득 궁금증이 들었습니다. 테스트 시나리오는 작성하면서 시나리오의 순서 역시도 중요하지 않을까? 하는 의문이 들었습니다. 단순한 기능들은 (예시로 들어주신 회원가입)은 테스트 시나리오의 순서에 큰 영향을 받지 않을 것 같으나 좀 더 복잡한 로직, 예를 들면 금액 계산과 같은 로직은 테스트 시나리오를 작성함에 있어서 순서를 신경 써야 할까요? 좋은 예시가 떠오르지는 않지만예약 시스템을 만들면서 테스트 시나리오를 짠다고 했을 때 테스트 시나리오의 순서대로 코드가 성장이 된다고 가정하면 테스트 시나리오를 작성하는 순서 역시도 중요한 부분 중 하나일 수 있겠다는 생각이 들었습니다.강사님은 테스트 시나리오를 작성 하실 때 순서를 크게 신경 쓰지 않으시나요? 아니면 로직의 흐름을 미리 어느정도 파악해 두시고 시나리오를 그 흐름에 맞춰 작성하시나요? 두서 없는 질문이라 정말 죄송합니다.
-
해결됨스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
13분쯤 테스트하다가 안 된다면?
저도 13분쯤에 create 테스트를 하다가 안 되어서 삽질했는데, 드디어 됐습니다.원인은createdAt, updatedAt에 값을 설정하지 않고 넣으려다 보니, null로 들어가서 에러가 발생했던 것이었습니다.그리고 mysql에 접속했을 때는 use article; 로 DB에 접근해야 합니다. 저는 use database;로 접근하고 있었네요. 이 과정에서 GPT의 도움을 많이 받았습니다. 13분쯤 진행다가 나오던 그 500 에러 로그는 애플리케이션을 확인해 봐야 하고요. 테스트 코드의 create 메서드에는 IDE의 설명도 같이 참고했습니다.왜 오류가 떴는지 알려주더군요.
-
해결됨Spring Boot TDD - 입문부터 실전까지 정확하게
@SpringBootTest 어노테이션의 classes 관련 질문 드립니다.
@SpringBootTest 어노테이션에 classes를 사용해 CommeceApiApp.class를 구체적으로 지정하시는 이유가 있으실까요?