- 학습 관련 질문을 남겨주세요. 구체적으로 적을수록 좋아요! - 마크다운과 단축키를 활용하면 글을 더 편하게 작성할 수 있어요. - 커뮤니티 질문 & 답변에 비슷한 내용이 있었는지 먼저 검색해보세요. - 서로 예의를 지키며 존중하는 분위기를 함께 만들어가요. - 잠깐! 인프런 서비스 관련 문의는 1:1 문의하기를 이용해 주세요 변경된 Claude 설정법 영상 [변경된 Claude 설정법 영상]만 하면 되는건가요? 아니면 claude_desktop_config.json에 "mcpServers": { "jetbrains": { "command": "npx", "args": ["-y", "@jetbrains/mcp-proxy"] } } ... 이거 복사 붙여넣기하는건 꼭 하고 진행해야 하는건가요? 근데 저게 뭘하는건지 궁금하긴하네요
안녕하세요~ 현재 아래 기술 스택을 사용한 API 서버가 존재합니다. Spring Boot 3 Kotlin JPA(JDBC) WebClient 예를 들면 아래와 같이 구성되어 있고, @RestController class SampleController( private val service: SampleService ) { @GetMapping("/sample") suspend fun start() { service.withoutDispatchers() } } @Component class SampleClient { private val webClient: WebClient by lazy { WebClient.builder() .baseUrl("https://api.com") .build() } suspend fun fetch(): Int { return webClient.get() .uri { uriBuilder -> uriBuilder.path("/number").build() } .retrieve() .awaitBody() } } interface SampleRepository : JpaRepository<SampleEntity, Long> @Service class SampleService( private val client: SampleClient, private val repository: SampleRepository, ) { suspend fun withoutDispatchers(): Int = coroutineScope { // non-blocking val deferred: Deferred<Int> = async { client.fetch() } // blocking val entity: List<SampleEntity> = repository.findAll() deferred.await() + entity.size } } Controller에서부터 suspend function으로 시작되면 Dispatchers.Unconfined를 사용하여 API 요청에 의해 할당받은 Tomcat 스레드를 그대로 사용하는 것으로 알고 있습니다. 이후 Service 레이어에서 suspend function이 동일하게 Dispatchers.Unconfined를 유지하기 때문에 요청 시 Tomcat 스레드는 그대로 사용되고 WebClient 요청 시 Dispatchers.IO를 사용하면, Tomcat 스레드와 별개로 Dispatchers 스레드 풀에서 스레드를 가져와 사용하는 것으로 알고 있습니다. 1번의 요청에서 Tomcat 스레드 1개 + Dispatchers 스레드 1개 = 총 2개가 사용됩니다. WebClient 요청 시 Dispatchers.IO를 생략하고 Dispatchers.Unconfined를 유지하면 , 코루틴의 재개 시 WebClient 응답을 동일한 Tomcat 스레드가 처리하게 하여 스레드 1개만을 사용하는 것이 서버에 더 효율적이지 않을까? 하는 생각이 들었습니다. 스레드가 Blocking되어도 WebClient의 NIO 이벤트 루프에 들어온 요청은 처리되어 응답에 대한 처리만 대기하고 있을 것이고, 테스트해보았을 때도 WebClient의 요청을 시작한 스레드가 JPARepository를 사용하는 코드에 의해 Blocking되어도 await()에서 문제 없이 응답을 받아올 수 있었습니다. 혹시 제가 생각하지 못한 또 다른 문제가 있을까요? 제가 혹시 잘못 알고 있는 부분이 있거나 Dispatchers.IO를 생략하지 못 하는 이유가 있다면 설명해주시면 감사하겠습니다!
안녕하세요. 최근 객체 간 의존 방향 고민에 많은 시간을 쏟고 있어 질문드립니다. 핵심 질문 도메인/서비스 간 의존 방향을 결정할 때 어떤 기준을 적용하면 좋을까요? "누가 누구를 알아야 하는가"에 대한 판단 기준이나 원칙이 있을까요? 저는 덜 중요한 개념의 변경이 중요한 개념에 영향을 주면 안된다고 생각하고 있었습니다. 그래서 중요한 개념이 덜 중요한 개념을 모르도록 코드를 짜려고 노력하는데요. 막상 개발할 때는 이게 잘 안되어서 고민에 시간을 많이 사용하거나, 타협하곤 합니다. 이런 상황이 이번 강의를 보면서도 나타나 질문글을 작성하게 되었습니다. 구체적인 상황 그런데 강의에서 download 메서드를 CouponService로 이동하는 과정을 보고 다음과 같은 의문이 들었습니다: 변경 후 구조: CouponService → OwnedCoupon, OwnedCouponRepository 의존 OwnedCoupon → Coupon, CouponRepository 의존 우려 사항: Coupon과 OwnedCoupon이 서로를 알게 되는 것이 순환 참조나 강결합을 유발하지 않을까? OwnedCoupon에 필드 추가 시, 기존에는 OwnedCouponService만 수정하면 됐지만 이제는 CouponService도 함께 수정해야 함 논리적으로는 CouponService에 download 기능이 있는 것이 맞아 보이지만, Coupon과 OwnedCoupon이 서로 알게 되는 것이 괜찮은 설계인가? 이런 고민에 시간을 많이 쓰다 보니 개발 시간이 부족하다고 느껴집니다. 마감을 위해 구현 후 리팩토링하는 방식으로 진행하고 있지만, 리팩토링을 못할 때도 많고 마음의 짐으로 남는 것 같습니다. 조언 부탁드립니다. 감사합니다.
안녕하세요. 항상 유익한 강의를 제공해 주셔서 감사드립니다. 입문 강의들을 제외한 모든 강의를 수강하며 많은 도움을 받고 있습니다. 다름이 아니라, 개인적으로 Kafka 관련 내용을 공부하던 중 KRaft 모드에 관한 내용이 공식 문서 및 여러 자료에서 업데이트되고 있는 것을 확인하게 되었습니다. KRaft는 Kafka의 아키텍처에서 중요한 변화를 가져온 만큼, 관련 내용을 강의나 추가 자료로 공유해 주신다면 수강생들에게 큰 도움이 될 것 같아 노티 드립니다. 항상 좋은 강의 제공해 주셔서 감사하며, 앞으로도 많은 배움을 기대하겠습니다.
RedisMessageBroker 가 @Service 로 관리 되기 때문에 싱글톤으로 관리 되는걸로 알고 있는데, 아래처럼 핸들러를 할당하는 경우 여러곳에서 setLocalMessageHandler 호출 시 문제가 발생할거 같은데 맞는건지 궁금합니다. fun setLocalMessageHandler(handler: (Long, ChatMessage) -> Unit) { this.localMessageHandler = handler }
안녕하세요 실무에서 '관리자(Admin) 예약 변경 기능' 정책을 두고 기획팀과 이견이 있어, 실무에서는 어떤 방식이 범용적인지 여쭙고 싶습니다. [시스템 상황] 유저가 예약할 때 다양한 할인(이벤트, 타임세일, 쿠폰, 기업지원 등)이 적용되며, 이 정보는 예약 시점에 스냅샷(Snapshot) 으로 저장됩니다. 현재 어드민(상담원/운영팀) 이 유저의 예약 시간/날짜를 변경하는 기능을 개발 중입니다. [이슈 사항] 기획상으로는 어드민에서 시간을 변경할 때도 모든 할인 조건을 '실시간'으로 재검증 하라고 합니다. 문제는 재검증 과정에서 '쿠폰 박탈' 같은 상황이 발생한다는 점입니다. 예시 상황: 유저가 5만원 짜리 예약에 5만원 이상 결제 시 사용 가능한 10% 쿠폰 을 씀. 어드민이 사정상(또는 유저 요청으로) 가격이 저렴한 타임이나 옵션으로 변경함 -> 결제액이 4만원 이 됨. 기획 요구사항: "최소 결제 금액(5만원) 조건을 불만족하게 되었으니, 자동으로 쿠폰 적용을 해제(원복)하고 금액을 재계산 한다." [제(개발자) 의견 및 고민] 저는 위 기획이 어드민 기능의 목적 과 UX(고객 경험) 에 맞지 않는다고 생각합니다. 고객 경험 훼손: 유저는 단지 시간을 바꿨을 뿐인데, 시스템이 엄격하게 검증해서 "조건 미달이니 쿠폰 뺏어가겠습니다"라고 하면 컴플레인 요지가 다분합니다. (유저 입장에선 혜택 유지를 원하니까요.) 데이터 복잡도: 이미 스냅샷으로 저장된 할인 정보를, 수정 시점에 다시 현재 기준의 마스터 데이터(쿠폰 유효기간, 최소금액 등)와 대조해서 '줬다 뺏는' 로직을 짜는 건 구현 복잡도 대비 실익이 너무 적습니다. 관리자의 재량: 어드민에서의 변경은 보통 '강제성(Override)' 을 띠는 경우가 많은데, 시스템이 칼같이 혜택을 잘라버리는 게 맞나 싶습니다. [질문] 보통 예약 도메인에서 관리자(Admin)가 개입하여 예약을 변경할 때 도, 이렇게 엄격하게 유저의 할인 자격(최소금액, 유효기간 등)을 재검증하여 박탈 시키는 게 맞나요? 아니면 어드민 권한 변경인 경우 "기존 스냅샷(혜택)을 최대한 유지" 해주거나, 가격 변동이 불가피하면 "취소 후 재예약" 을 하는 프로세스가 더 일반적인가요? 개발자로서 이 복잡한 '조건부 쿠폰 회수' 로직을 방어하고 싶은데, 설득력 있는 논리가 필요합니다. 조언 부탁드립니다!
안녕하세요. 싱글톤 관련 질문 드립니다. 특정한 의문점에 대한 질문은 아니고요. 스프링 컨테이너는 핸들러나 서비스 빈을 싱글톤으로 관리하게 되는데, 혹시 강의에서 등장한 자바와 코틀린의 싱글톤 사용 방식의 차이에 의해 발생하는 스프링 싱글톤 관련된 이슈가 있는지 궁금합니다. 싱글톤 관리는 언어와 관계없이 스프링 컨테이너가 맡게 되니 별 상관이 없을 것으로 예상되긴 합니다만.. 혹시 싶어 질문 드립니다. 감사합니다.
안녕하세요! 수업 잘 듣고 있습니다. 사소한 내용이긴한데.. OrderService.create 에서 OrderKeyGenerator 객체를 를 주입받아 generate() 를 호출해서 orderKey 를 생성하는 부분에서 OrderKeyGenerator class 는 상태를 가지지도 않고 Property 를 가지지도 않는데 static method, 함수로 구현 되어도 되지 않았을까 하는 생각이 들었는데요. 어떤 고려사항이 있는지 궁금합니다. static 이든 함수든 객체 메서드이든 상관 없다? 나중에 OrderKeyGenerator 가 확장되는 것이 고려된 것? OrderSerivce 에서 사용하는 기능이니 주입되는 것이 더 응집되어 보여서 더 좋다? 그냥 함수를 가져다 쓰는 것보다 객체를 주입하는 쪽이 테스트 하기 좋다? generate 가 순수함수가 아니라서? class OrderKeyGenerator { fun generate(): String { return Base64.getUrlEncoder().withoutPadding().encodeToString( ByteBuffer.allocate(16).apply { UUID.randomUUID().also { putLong(it.mostSignificantBits) putLong(it.leastSignificantBits) } }.array(), ) } }
안녕하세요. 상속과 별로 연관된 질문은 아닌 듯 하지만 강의에서 나온 부분에 궁금증이 생겨 질문 남깁니다. val swimAbility: Int get() = 3 이라는 예제 코드를 작성하셨는데요. 코틀린은 어차피 필드를 선언하면 게터, 세터를 만들어주고 필드 선언 시 디폴트 값도 지정해줄 수 있는데 그렇다면 위와 같은 형태의 커스텀 게터는 굳이 구현할 필요 없는 것 아닌가? 하는 생각이 듭니다. 그냥 초기값 3을 갖는 필드를 선언하기만 하면 게터까지 알아서 만들어질 테니까요. 그냥 인터페이스의 게터 상속 의도를 표현하기 위해 별 의미나 실 용례는 없는 코드를 작성하신 거라고 봐도 될지? 아니면 저런 방식의 커스텀 게터에 제가 이해하지 못하는 어떤 의미가 있는 것일지가 궁금합니다. 감사합니다. ㅇ
상황 정리 저희가 매장 관리자용 통합 예약 관리 시스템 을 개발하고 있습니다. 현재 시스템 구조 [외부 예약 플랫폼 (네이버 같은)] ↓ 자동 연동 [매장 POS 시스템 (티오더 같은)] ↓ API 폴링 [우리 통합 관리 시스템] 고객이 외부 플랫폼에서 예약하면 POS에 자동으로 들어옴 우리는 POS API를 폴링해서 예약 데이터를 가져옴 우리 어드민에서 직접 예약 등록 기능도 곧 추가 예정 문제 상황 POS 업체에 확인해보니: API에서 외부 플랫폼 예약 구분이 안 됨 → 구분값 추가 예정 외부 예약은 원칙적으로 수정 불가 현재는 수정이 되지만 플랫폼 API 키가 연결 안 되어 사실상 불가능 DB만 바꿔서는 의미 없고, 외부 플랫폼 API 재호출이 필요 POS와 외부 플랫폼 간 연동이 아직 불완전한 상태 논의된 두 가지 방향 A안 (readonly 방식) - 우리 어드민 생성 예약 → POS 직접 등록 (수정 가능) - 외부 플랫폼 예약 → POS에서 폴링해서 조회만 (수정 불가) - UI에서 "외부 예약" 표시하고 수정 버튼 비활성화 - 수정 필요시 원본 플랫폼 바로가기 링크 제공 B안 (통합 수정 방식) - 모든 예약을 우리 시스템에서 직접 수정 가능하게 - 외부 예약 수정 시 POS API → 외부 플랫폼 API 호출까지 처리 장단점 분석 A안 장점 각 시스템의 책임 범위가 명확함 동기화 정합성 이슈 없음 외부 플랫폼 정책 변경에 영향 안 받음 여러 플랫폼을 한 곳에서 조회만 해도 관리자 리소스 절감 효과 A안 단점 수정은 여전히 각 플랫폼에서 해야 함 "진정한 통합 관리"는 아님 B안 장점 완전한 통합 관리 경험 관리자가 한 곳에서 모든 예약 제어 B안 단점 외부 플랫폼 API 직접 연동 불가 (계약 주체가 매장) POS가 외부 플랫폼 제어 API를 제공해야 하는데 현재 없음 POS-외부 플랫폼 양쪽 동기화 복잡도 높음 외부 플랫폼 정책(취소규칙 등) 변경 시 계속 대응 필요 문제 발생 시 책임 소재 애매 질문 이런 다중 오리진 데이터를 통합하는 시스템 에서: readonly로 가는 게 맞을까요, 아니면 수정까지 구현해야 할까요? 단계적으로 접근한다면 어떤 순서가 좋을까요? 1단계: 통합 조회만 2단계: POS가 API 제공하면 그때 수정 추가 비슷한 사례에서 일반적으로 어떻게 접근하나요? 현재 상황에서는 A안(readonly)이 합리적이라고 판단됩니다. 하지만 시간이 지나서 다음 조건들이 충족된다면: POS에서 외부 예약 플랫폼 식별값을 제공 외부 예약 플랫폼 API를 저희가 제공받을 수 있음 그때는 어떤 아키텍처로 가야 할까요? 옵션 1: 직접 호출 방식 [우리 시스템] → [외부 플랫폼 API] (직접 호출) → [POS API] (동기화용) 우리가 외부 플랫폼 API를 직접 호출 POS는 조회 + 동기화 확인용으로만 사용 옵션 2: POS Proxy 방식 [우리 시스템] → [POS API] → [외부 플랫폼 API] POS가 외부 플랫폼 제어 API를 제공하도록 요청 우리는 POS API만 호출하면 POS가 내부적으로 플랫폼 API 처리 외부 플랫폼 변경사항은 POS가 책임 옵션 3: readonly 유지 [우리 시스템] → [POS API] (조회만) 기술적으로 가능해져도 readonly 유지 각 플랫폼 바로가기만 제공 어떤 방식이 일반적이고, 각 옵션의 trade-off는 무엇인가요? 특히 옵션 1 vs 옵션 2에서: 우리가 직접 여러 외부 API를 관리하는 게 나을까요? 아니면 POS가 Proxy/Gateway 역할을 하게 하는 게 나을까요?
안녕하세요! PG 결제 승인 API 구현 중 고민이 되는 부분이 있어서 질문드립니다! PG사로 부터 /callback/success 등과 같이 콜백 url로 요청을 받았을때 결제 승인을 서버에서 진행하는 플로우인데 결제 승인 요청 전 결제 검증 PG 결제 승인 API 호출 정상 승인 or 승인 실패 시 transaction_history 저장 의 흐름인 것 같은데 추가적으로 3번에서 정상 승인 시에 PG사로 부터 응답받은 paymentKey, amount 등을 요청한 paymentKet, amount와 동일한지 검증이 필요할까? 라는 생각이 들었습니다. 궁금한 점은 실무에서 PG사 연동 시에는 결제 승인 응답 후 검증 로직을 다루는지? 다룬다면 실제 승인 요청 내역과 응답 내역이 다르다면 어떻게 처리하는지? (클라이언트로 응답, 불일치 시 보정 전략 등..) 외부 API 호출 시 서킷 브레이커를 사용하는 걸 선호하는지? 정도가 있습니다! 제미니님 덕분에 항상 많이 배워갑니다 감사합니다~!
강사님의 코드를 보니 Question 클래스 등에 id, userId, title, content 등만 넣어두신 것 같은데 일반적으로 자주 표현되는 다른 필드를 표현하려면 어떻게 하는 것이 좋을까요? 예를 들어 QnA 조회시 질문 목록에서 질문 작성자의 이름이 표시되는 형태가 많습니다. 이때 그렇다면 QnAResponse 에 questionAuthor 필드가 있어야 할 것 같은데 해당 필드가 추가된다면 어떻게 username 정보를 넣어주어야 할지 궁금합니다. 1안. Question 클래스가 userId 대신 User 클래스를 가지고 있는다... 2안. Controller에서 user 목록을 조회해서 response 팩토리 메서드에서 매핑한다. 2안이 더 나을 것 같긴 합니다만, 리스트이다 보니 매핑로직이 복잡해 질 것 같기도 하고... qnsList->question->userId 모아서 userList조회... map생성 후 매핑 등등 이런 과정이 괜찮은건지 궁금합니다. 또 2안이 더 나은 방법이라면 response에 노출해야하는 join 필드 5-6개 처럼 많을때는 어떻게 처리하시는 편인지도 궁금합니다
선생님 안녕하세요. 아래 함수만 추가 하고 back버튼을 클릭 한번만 해도 오류 없이 자동으로 앱이 종료 됩니다. 로그도 다르게 나옵니다. 전체 소스 공유 드립니다. https://drive.google.com/file/d/1pywWeGHuAAZb0a0nC1IZZdje1wLZxlLv/view?usp=sharing override fun onBackPressed()
안녕하세요 결제 코드느끼기 강의를 보며 궁금한점이 있어서 질문을 남깁니다. 여러 주문들을 동시에 넣었고 createPayment가 되고 PG사로부터 success가 콜백 호출 된다 했을때, 동시성 문제가 우려되는데요 각 주문마다 point 혹은 coupon을 쓴다고 했을때, 고객이 가진 point 이상으로 point가 차감된다든지, 쿠폰 재사용 문제를 직면했을때 예외처리가 없어보이며, 이 때문에 이를 복구하는 방안같은건 없어보입니다. (괜히 예외처리를 했다가 고객의 돈이 빠져나가고 결제상태가 안바뀔 염려때문) 그럼에도 각 Value Object에서 valid및 예외처리하는 로직이 success api에 추가할 수 있을까요? 아니면 주문 결제 전 단계에서 막으면 좋을까요? 아니면 그럴 가능성이 자주는 없으니, 결제 상태는 Ready인 부분을 찾아서 수동 수정하는것도 방법이라고 보시나요?