묻고 답해요
169만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨"AI 딸깍의 시대" 원리로 돌파하는 Node.js와 CS Part1 - V8과 코어 해체기
ai가 만든 강의인가요?
목소리도 그렇고 tts가 읊어주는 것 같은데, 그냥 ai로 대충 장료 만들고 tts 입힌 강의인거 아니죠...?
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
강의 중복 확인 요청
섹션 9부터 중복으로 내용이 있는데 확인 바란다
-
미해결시스템 디자인 첫걸음: 면접에서 돋보이는 백엔드 아키텍처 설계하기
캐시전략 - Write-behind
안녕하세요. 강사님캐시전략 - Write-behind 전략을 설명해주셨는데,인스타라이브나 유튜브라이브에서 좋아요를 한 사용자가 여러번 누를 수 있는데, 이때가 아마 Write-behind 전략을 적용할 수 있을 거 같습니다.1. 좋아요를 레디스 캐시에 카운트 증가2. 좋아요 누른 개수를 몇 초마다 flush로 카프카 큐에 발행3. 카프카 consumer에서 db저장 이런 방식으로 설계가 가능할 거 같습니다. 강의에서는 Write-behind DB에 나중에 저장한다고 말씀하셨는데 그럼 이런 라이브 상황에서 DB에 좋아요를 언제 저장하는 것이 바람직할까요? 그 기준을 어떤 식으로 잡으면 좋을지도 선생님의 고견이 듣고 싶습니다.좋은 강의 감사합니다.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
중복내용 제보?!
안녕 킬구형 강의는 구매한지 오래됐지만 지금에서야 공부하고 있어 별건 아닌데! 청크처리와 트랜잭션 부분이 2번 들어가있어서 알려줄려고! 킬구형 덕분에 싸게 구매해서 정말 공부 열심히 하고 있어!다음것도 기대할게!
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
궁금한점이 여러개 생겼습니다.
안녕하세요, 2회독 하는중입니다. 확실히 강의 활용하면서 진행하니깐 느끼기(?)가 뭔지 알것같고 궁금한점이 생기네요. CouponService 에서 이미 다운받은 쿠폰은 내려주지 않는 로직을 만들면서 궁금한점이 여러개 생겼습니다.작성하면서 정리하니깐 궁금한점이 계속 꼬리물어서 생긴다고 해야하나 그래서 의식의 흐름대로 적는 것 같아서 미리 죄송합니다 🥲/// CouponService public List<Coupon> getCouponsForMenus(Principal principal, Collection<Long> couponIds) { Set<Long> applicableCouponIds = couponFinder.findApplicableCouponIds(couponIds); Set<Long> downloadedCouponIds = issuedCouponFinder.findDownloadedCouponIds(principal.getId()); Set<Long> downloadableCouponIds = applicableCouponIds.stream() .filter(id -> !downloadedCouponIds.contains(id)) .collect(Collectors.toSet()); return couponFinder.findAllById(downloadableCouponIds); } // CouponFinder public Set<Long> findApplicableCouponIds(Collection<Long> menuIds) { List<CouponTargetEntity> menuTargets = couponTargetRepository.findByTargetTypeAndTargetIdIn( CouponTargetType.MENU, menuIds ).stream().filter(CouponTargetEntity::isActive).toList(); List<CouponTargetEntity> categoryTargets = couponTargetRepository.findByTargetTypeAndTargetIdIn( CouponTargetType.MENU_CATEGORY, menuCategoryRepository.findByCategoryIdIn(menuIds).stream() .filter(MenuCategoryEntity::isActive) .map(MenuCategoryEntity::getCategoryId).collect(Collectors.toSet()) ); return Stream.concat(menuTargets.stream(), categoryTargets.stream()) .map(CouponTargetEntity::getCouponId) .collect(Collectors.toSet()); } CouponService 에서 implement 계층 CouponFinder, IssuedCouponFinder 를 의존하고 있는 상황에서 각 계층끼리 소통할 때강사님 Q/A 답변중에서 가능한 db 엔티티 대신에 개념객체를 넘기는 방향으로 설계하는걸 지향하신다고 말씀하신 답변이 기억이 나는데요, 지금 상황에서는 개념객체까지 변환하는것보다는 id 컬렉션만 뽑아내서 넘기는게 더 효율적이고 깔끔한 것 같습니다.이런 패턴(?) 이 자주 나올 것 같아서 괜찮은지 궁금 합니다.꼭 id 컬렉션을 넘기는게 아니더라도 entity를 반환해야만 매핑하기 편한 경우가 많을 것 같더라구요회원/비회원 요구사항https://inf.run/GTxAx해당 Q/A 를 보기도 했고 마침 강의 활용해서 커피 판매 어플리케이션을 만들고 싶어서 비회원처리가 필요했습니다.public class PrincipalArgumentResolver implements HandlerMethodArgumentResolver { private static final String PRINCIPAL_ID_HEADER = "Gu-Coffee-Principal-Id"; private static final String PRINCIPAL_TYPE_HEADER = "Gu-Coffee-Principal-Type"; @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.getParameterType().isAssignableFrom(Principal.class); } @Override public @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request == null) throw new CoreException(ErrorType.INVALID_REQUEST, null); Authenticated annotation = parameter.getParameterAnnotation(Authenticated.class); String id = request.getHeader(PRINCIPAL_ID_HEADER); String type = request.getHeader(PRINCIPAL_TYPE_HEADER); validatePrincipal(annotation, id, type); return Principal.of(id, type); } private void validatePrincipal(Authenticated annotation, String id, String type) { boolean isRequired = (annotation != null && annotation.required()); if (isRequired) { if (id == null) throw new CoreException(ErrorType.UNAUTHORIZED, null); if (!PrincipalType.USER.name().equals(type)) { throw new CoreException(ErrorType.UNAUTHORIZED, "회원 전용 서비스입니다."); } } if (type == null) { throw new CoreException(ErrorType.INVALID_REQUEST, null); } } } @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Authenticated { boolean required() default true; } 저는 Authenticated 라는 메타 어노테이션을 사용해서@GetMapping("/v1/issued-coupons") private ApiResponse<List<IssuedCouponResponse>> getIssuedCoupons(@Authenticated Principal principal) { List<IssuedCoupon> issuedCoupons = issuedCouponService.getIssuedCoupons(principal); return ApiResponse.success(IssuedCouponResponse.from(issuedCoupons)); } @PostMapping("/v1/coupons/{couponId}/download") private ApiResponse<?> download( Principal principal, @PathVariable Long couponId) { couponService.download(principal, couponId); return ApiResponse.success(); } public void download(Principal principal, Long couponId) { if (principal.getType().equals(PrincipalType.GUEST)) { throw new CoreException(ErrorType.UNAUTHORIZED, "비회원은 쿠폰을 다운로드할 수 없습니다."); } 애초에 회원만 접근 가능한 api 는 어노테이션으로 처리하던가 서비스 단에서 예외를 던지게 할 수도 있을 것 같아서 이렇게 만들어 봤습니다.이런식의 접근이 괜찮은지당장은 인증객체(Principal)? 랑 User 랑은 다른 개념일 것 같아서 강의내 User 대신에 사용했습니다.@Table(name = "cart_item") @Entity public class CartItemEntity extends BaseEntity { private Long userId; private String guestKey; @Enumerated(EnumType.STRING) private PrincipalType principalType; private Long menuId; private Long quantity; } public class Cart { private Principal principal; private List<CartItem> items; } 마지막으로 장바구니에 비회원도 담을 수 있다는 요구사항이 있다고 가정하면 테이블에는 userId 만 둬서 null 로 구분하는 것 보다 key 필드를 추가하고public interface CartItemRepository extends JpaRepository<CartItemEntity, Long> { @Query("SELECT c FROM CartItemEntity c " + "WHERE (:type = 'USER' AND c.userId = :id) " + "OR (:type = 'GUEST' AND c.guestKey = :key)") List<CartItemEntity> findByPrincipal( @Param("type") String type, @Param("id") Long id, @Param("key") String key ); } 이런식으로 쿼리로 분기처리해야지 생각했는데요. 예전 강사님 Q/A 답변 중에서 쿼리중심의 어플리케이션이 되는걸 지양한다는 느낌의 답변을 봤던 것 같습니다.AI 한테 물어봤을때는 해당 로직은 필터링 목적이니 쿼리로 처리하는게 성능상 효과적이라는 답변을 줬는데요.List<IssuedCouponEntity> issuedCoupons = issuedCouponRepository.findByUserId(userId) .stream() .filter(IssuedCouponEntity::isActive) .toList(); isActive 인 데이터를 가져올 때 강사님이 findByXXAndStatus 로 한번에 가져오거나 혹은 위처럼 filter로 처리하는 두가지 패턴을 보여주셨습니다.이걸 처음 봤을 때, 미세한 성능보다는 filter 로 직관적으로 활성상태인 데이터만 가져온다는 목적을 코드로 보여주는게 더 괜찮겠다고 생각했는데요.근데 이것도 결국 필터링 목적이니깐 메서드 네이밍(findByXXAndStatus)으로 처리하는게 일관성 있는게 아닌지 궁금합니다.
-
미해결AI 시대에 살아남기: Supabase로 백엔드 뚝딱!
수파베이스 ORM 질문
안녕하세요.수파베이스 ORM 섹션을 듣고나니 일반적인 백엔드 서버와 api 라우트를 정의하고 데이터를 주고받는게 아닌 클라이언트에서 직접 수파베이스 ORM를 호출할 수 있는 것으로 확인되는데요!현재 회사에 프론트엔드 개발자 2명이고 백엔드 지식이 많지않아 next.js + 수파베이스로 MVP 검증부터 진행할 것같습니다.수파베이스로 MVP 검증후 별도의 백엔드 서버로 분리하게되었을때(분리가 꼭 필요한지도 사실 잘 모르겠습니다.) 분리비용을 최소화히기위해 api호출 과정을 next.js의 api라우트를 무조건 거쳐서 수파베이스를 접근하게하려고하는데 이런 과정이 유의미한 작업이 될 수 있는지 궁금합니다.
-
미해결AI 시대에 살아남기: Supabase로 백엔드 뚝딱!
트리거 질문
안녕하세요. 프론트엔드만하다가 강의보고 백엔드에대해 알아가는중입니다. 백엔드쪽은 아예 기반이 없다보니 하나하나 해보면서 따라가고있는중입니다. 1. 트리거는 ui로 설정을안하고 SQL 에디터로 설정을 해주셨는데 따로 이유가 있을까요??2. 트리거와 그 안에서 작성해주신 업데이트 함수가 별도로 관리되는것같더라고요.functions가 유틸함수고 Triggers가 시점과 적용대상(어느 테이블에 적용할지?)를 관리하는 영역으로 이해하는게 맞을까요?3. 트리거는 테이블영역에서 적용이 불가능한가요? RSL처럼요!! 뭔가 분산되어있는 느낌이 있어서요. 4. 숙제내용 제출
-
해결됨"AI 딸깍의 시대" 원리로 돌파하는 Node.js와 CS Part1 - V8과 코어 해체기
3강 질문
💡[CS 실무 Point: OS 계층의 역량 활용 (epoll / kqueue)] 단일 스레드라고 해서 컴퓨터가 정말로 혼자 일하는 것은 아닙니다. 파일 읽기나 네트워크 통신 같은 무거운 작업은 Node.js가 직접 처리하지 않고, 운영체제 커널이 제공하는 고성능 이벤트 통지 API(Linux의 epoll, macOS의 kqueue 등 시스템 콜)를 통해 운영체제에게 철저하게 위임(Offloading)합니다. 즉, Node.js의 메인 스레드는 교통정리만 아주 빠르게 수행할 뿐, 실제 무거운 짐은 OS 커널이 백그라운드에서 나르고 있는 것입니다. 안녕하세요, 위 설명에서 질문이 있습니다.운영체제에 위임하는 작업과 libuv 스레드 풀의 워커 스레드가 어떤 연관이 있고 어떻게 유기적으로 동작하는지 궁금합니다.
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
강의 듣는 중인데,
1강에서 자료 다운받기? 한 것은 언제쯤 보는 걸까요?? 강의 다 끝나고 혼자서 공부하는건가요?? 어떤 순서로 공부를 해야하는지요?
-
미해결AWS SAA-C03 자격증 벼락치기 - 딱 163문제로 2주만에 합격하기
36강 오탈자가 있는 거 같습니다.
안녕하세요,36강 1분 10초쯤에AWS Glue의 ETL에서 Tarnsform > Transform 오타인 거 같습니다.
-
미해결스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 캐시 전략
Service Create/Update Record 운용과 Delete Record 미운용의 차이 질문
안녕하세요, 선생님! 강의 들으면서 Service 및 Cache Handler 구성간 Create/Update <-> Delete 간의 Return Record 여부 차이에 대해 질문드리고자 합니다. 서비스도 그렇고, 핸들러도 그렇고, Return type이 Create/Update는 전달받은 Record를 Entity Context에 적용한 객체인데, delete의 경우 void로 운용하시는 것을 보고 어떤 차이점이 있는지 궁금하여 질문드리게 되었습니다. create, update 모두 반영 이후의 내역을 바로 반환하여 보여준다는 의미로 생각하였는데, delete를 보면 그런 것 같지는 않아서 따로 다른 의미가 있는지(실무에서 이렇게 많이 사용한다던가), 별 의미가 없는지 구체적으로 문의드리고자 합니다. 감사합니다.
-
해결됨"AI 딸깍의 시대" 원리로 돌파하는 Node.js와 CS Part1 - V8과 코어 해체기
2강 nodejs 3단계 설명 질문
2.4 Node.js의 3단계 분업 아키텍처 자바스크립트 코드가 운영체제를 움직이는 과정은 세 단계의 협업으로 이루어집니다.자바스크립트 코드 작성: 개발자가 비즈니스 로직을 작성합니다.V8 엔진의 통역: 자바스크립트를 C++가 이해할 수 있는 형태로 통역합니다.C++ 코어 및 바인딩(Bindings): 통역된 지시를 받아 운영체제(OS)에 직접 명령을 내립니다. 이때 C++는 현장의 작업 반장 역할을 수행하며 실제 파일이나 네트워크를 제어합니다.위 내용에서 v8의 통역 이후 부분이 이해가 잘 가지 않습니다. v8 엔진의 결과물은 C++과 관계없이 바이트코드나 기계어가 되지 않나요? 그리고 js만으로 불가능한 os 작업이 나오면 v8 실행 중에 미리 C++로 만들어 놓은 모듈을 호출하는 식으로 동작하는게 아닌지 문의드립니다.감사합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
Sequence 관련 질문
저는 review image reordering을 염두에 두고 sequence를 계속 가져가는 방향으로 결정했습니다.제미니님은 실무에서 이렇게 염두에 두고 구현이 조금 더 복잡해지더라도 이런 특정 필드나 기능을 가져가는것을 오버엔지니어링이라고 생각하여 피하시는 편인가요? 어떤 기준으로 결정하시는지 궁금합니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 레거시와 AI 활용편
Image Only Query
image only query를 설명해주실때 stable pagination 때문에 조인을 사용하신다고 이해했습니다. 저는 다른방식으로 구현해보았는데 제미니님의 의견이 궁금합니다. 코드를 보면 나중에 image를 fetch 또 하게 되는데 이렇게되면 image only query를 ReviewImageEntity에 reviewId, status 인덱스를 걸고SELECT review FROM ReviewEntity review WHERE review.targetType = :targetType AND review.targetId = :targetId AND review.status = :status AND EXISTS ( SELECT image.id FROM ReviewImageEntity image WHERE image.reviewId = review.id AND image.status = :status 이렇게 구현하는 방식이 데이터량이 많아진다면 효율적이지 않을까 싶어서 구현해봤습니다.
-
해결됨10,000++억의 데이터를 다루는 카카오 면접관의 MySQL
라이브 운영중인 환경의 테이블에 인덱스 추가시 고려사항
hong님 안녕하세요! 라이브 운영중인 테이블에 인덱스 추가시 고려할 사항이 궁금합니다! psotgresql이긴 하지만 금일 오전에 데이터 1800만건이 있는 테이블에 인덱스 추가를 했더니 cpu 100% 치솟는 장애 직겨탄을 맞았습니다.. (15분간 앱 사용 중단 ㅠㅠ)뒤늦게 찾아보니 락을 잡지 않는 옵션을 추가했어야 하더군요. 새벽에 작업, 일시적인 디비 스펙업 정도만 떠오르네요. 몇천만건 ~ N억건 데이터가 있는 테이블에 인덱스 생성시 고려할 사항이 무엇들이 있는지 궁금합니다!
-
해결됨Spring Boot DDD 실전: 주문 시스템으로 배우는 도메인 설계
DDD 는 마이바티스와 잘 맞지 않는건가요?
안녕하세요.DDD 관련 강의나 블로그를 보면대부분 JPA 로 설명해주시더라구요. 마이바티스도 실무에서 오히려 더 폭 넒게 쓰이는 것 같은데 마이바티스로는 DDD 를 적용하기 어려운걸까요?
-
해결됨Spring Boot DDD 실전: 주문 시스템으로 배우는 도메인 설계
스프링부트 버전 문의드립니다.
안녕하세요. 부트버전을 3.5 로 설정해서 수강해도 괜찮을까요. 회사에서 아직 4.x 버전 업 계획이 없어서요.
-
미해결죽음의 Spring Batch: 새벽 3시의 처절한 공포는 이제 끝이다.
Json 요청 처리
형 나 지금 너무 재밌어서 잘 따라하던중 별거 아닌거에서 막혀서 좀 힘들어형이 알려준 json 파라미터 넘기는 방법으로 해도 안되고 gpt 찾아서 진행 한거도 다 안돼는데 윈도우 환경에서 좀 힘든걸까 ?? 다른 수강생분이 올려준거도 봤는데 답변에 달아준 방법도 동작하지 않아 @Bean public JsonJobParametersConverter jobParametersConverter() { return new JsonJobParametersConverter(); } @Bean @StepScope public Tasklet terminatorTasklet( @Value("#{jobParameters['infiltrationTargets']}") String infiltrationTargets ) { return (contribution, chunkContext) -> { String[] targets = infiltrationTargets.split(","); log.info("⚡ 침투 작전 개시"); log.info("첫 번째 타겟: {} 침투 시작", targets[0]); log.info("마지막 타겟: {} 에서 집결", targets[1]); log.info("🎯 임무 전달 완료"); return RepeatStatus.FINISHED; }; }
-
해결됨카카오, 토스 개발자가 알려주는 수백개의 MSA 환경에서의 성능 보장을 위한 RPC 처리 기법
gRPC 실무에서 질문
이제 앞으로 3개만 더 들으면 완강이네요! 빠르게 gRPC를 공부할수 있어서 좋았습니다. 강의를 마무리해가니 궁금한 점이있어 질문 남깁니다.마이크로서비스가 1000개 이상되는 회사에서 데이터팀 백엔드 인턴으로 근무를 할 예정인데 데이터팀이다 보니 서비스들 전체를 아우르는 일을 해야한다고 들었습니다. 그래서 gRPC에 대해서 공부해오면 좋다고 해서 강의를 수강하게 되었습니다. 처음에 회사에 들어가면 어떤식으로 서비스들의 gRPC를 분석해야할까요? 혹시 추천해주시는 순서가 있으실까요? 예를 들어서 .proto파일을 먼저 확인한다 -> 등등성공적인 백엔드 인턴을 위해서 추가적인 조언이 있으시다면 감사하겠습니다.
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
다양한 관점의 코드 경험을 위해 개선하지 않은 코드
안녕하세요. 제미니님 유튜브 부터 인프런까지 참여하며 굉장히 많은 인사이트를 얻고있어 무한한 감사 인사를 올립니다. 질문강의를 수강하며 제미니님이 던져준 키워드를 어떻게 곱씹어야하지? 라는 생각을 하며 두 가지 정도 질문을 드리게 되었습니다. Q1. "저같은 경우는 뭐 컴포넌트 같은 걸 좀 쪼개서 만들고 싶은데, 일단은 여러분들이 좀 혼합된 걸 느끼게 하려고 제가 풀어 놨어요" - 결제 코드 느끼기 13:17이렇게 제미니님이 생각했던 코드를 보고 싶은데, 이 코드는 신규 강의였던 "레거시 다루기" 에서 개선 작업을 하나요? 아니면 저희에게 열린 사고를 던져주고 넘어가는걸까요? Q2. "success 메서드에 트랜잭셔널을 사용하는 것도 할 말이 많은데 기본적인 로직에서는 문제는 없다." - 결제 코드 느끼기 13:58이 내용에서도 혹시 개선하는 부분도 질문 1번과 같이 레거시 다루기 강의에서 개선 하시나요?개인적으로 success 에서 트랜잭션 어노테이션을 빼고, 저장하는 로직을 한 군데 모아서 거기 사용할 것 같은데 제미니님은 어떻게 하시는지 궁금하네요!