묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
헥사고날 아키텍처에서의 배치, 시큐리티, 비동기 이벤트 처리는 어떻게 하나요?
안녕하세요, 이번 강의를 통해 처음으로 헥사고날 아키텍처에 대해서 공부하고 있는 사람입니다. 헥사고날 아키텍쳐를 지키면서 배치, 시큐리티, 이벤트 처리 등등 다양한 기술을 어떻게 사용하나요?제가 공부해본 바로는1. 배치: 애플리케이션 계층에 배치를 통해 이루어질 api를 만들어두고, 어댑터 계층엔 배치(Job, Step, Writer, Reader등 )에 관한 설정들을 위치하게 한다.2. 시큐리티: 전부 어댑터에 위치한다. 이벤트 처리: 이벤트는 도메인으로 간주하고 도메인 계층에 위치시키고, 이벤트 리스너는 어댑터 계층에 위치시킨다. 이벤트를 발행시키는 로직은 애플리케이션 계층에 위치하고, ApplicationEventPublisher 같은 경우는 추상화됐다고 판단하고 그냥 사용하거나, 혹은 인터페이스를 따로 만들어서 사용한다.이정도인데 큰 흐름에서 제가 이해한 게 맞을까요? 특히 궁금한 건 "이벤트가 도메인으로 간주되어도 문제가 없는지" 입니다.(무조건 도메인이기 보다는 로직을 처리하기 위해 존재하는 dto로 볼 수도 있는 거 아닌가 싶어서요.)다른 기술들을 헥사고날 아키텍쳐에 적용시킬 때 주의할만한 사항들도 따로 존재를 할까요?
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
어댑터에서 도메인에 직접 의존하는 경우에 대해
안녕하세요.좋은 강의 잘듣고 많이 배우고 있습니다. 좋은 강의 만들어주셔서 감사합니다.다름이 아니라, 어댑터에서 엔티티에 의존성을 가지는 것이 크게 문제되지 않는다고 말씀주신 내용에 의문이 있어 질문드립니다! 어댑터에서 도메인에 직접 의존하는 것을 막기 위해서 변환 역할을 하는 매퍼 클래스나 DTO에서 엔티티를 자기 자신으로 변환하는 로직을 가지는 것은 어떨까요? 타이트하게 룰을 잡는 케이스를 가정한다면, application layer 내부에 port가 존재할 것이고 이 port에서 return 하는 dto도 application layer일 것이고, 이 dto 안에서 Entity를 받아서 자기 자신으로 변환하는 로직을 가진다면 entity가 application 밖으로 나가지 않을 수 있지 않을까요?(controller, repository 등 마찬가지입니다)그리고 dto를 application에서 변환하는 것이 로직의 침투라고 표현하시기도 했는데, 그렇다면 provided port 역시 어댑터의 요구가 침투하는 구조라고 볼 수도 있을 것 같기도 합니다..(생각해보니 이상적으로는 계층별로 DTO를 생성하는게 맞다고 생각은 들지만, "엔티티를 반환하는 트레이드오프가 굉장히 효율적이고 정당하다"라고 말씀하신 것 같다고도 생각이 듭니다) 강의에서 항상 기술이 등장한 배경과 사상을 이해하고, 이를 바탕으로 정당하게 규칙을 스스로 정하는 것을 강조하시는 것 같습니다. 그래서 강의에서 말씀하신 내용이 비슷한 맥락으로, "절대 노출되면 안된다"라는 것에 대한 반박이라고 받아들여지긴 합니다만.. 그래도 바깥쪽으로 노출하지 않는 것이 의존성 관리 차원에서 더 좋지 않을까하는 생각에 질문드립니다!
-
해결됨토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
Member 도메인이 PasswordEncoder를 받는 구조 질문 있습니다.
예제에서는 도메인에 별도 PasswordEncoder 인터페이스를 정의해 사용하고 있습니다. 만약에, Member 도메인이 Spring Security의 PasswordEncoder 인터페이스를 직접 의존한다면, 구현체가 아니라 인터페이스를 참조하더라도 순수 도메인 설계 관점에서 위반으로 봐야 할까요? 저는 인터페이스 의존이라 괜찮을 수 있다고 생각했지만 AI는도메인에서는 자체 PasswordEncoder 포트만 사용하고, Spring Security PasswordEncoder는 인프라 어댑터에서 위임하는 것이 좋다.고 제안했습니다. 토비님은 어느 쪽이 더 적절하다고 보시는지, 판단 기준도 함께 듣고 싶습니다.
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
MemberService와 EmailSender 책임 분리에 대한 질문
안녕하세요, 토비님. 강의 초반에 말씀해 주신 것처럼, 리팩토링 과정에서 “제가 했다면 어떻게 했을까”를 계속 생각해 보며 토비님의 의사결정 과정을 따라가고 있습니다. MemberService.register() 메소드에서 emailSender.send(...)를 sendWelcomeEmail()로 분리하시는 과정을 보며 두 가지 고민이 생겼습니다. 첫째, 환영 이메일의 내용이나 정책이 변경될 때마다 MemberService의 코드가 함께 변경되어야 한다면, 이는 SRP 위반에 해당하지 않는지에 대한 고민입니다. 이 경우 환영 이메일 전송에 대한 책임을 EmailSender 인터페이스 쪽으로 옮기는 것이 더 적절한지 궁금해졌습니다. 둘째, 만약 EmailSender 인터페이스에 해당 메소드를 추가한다면, 구현체가 늘어날수록 인터페이스가 비대해지거나 향후 구현 복잡도가 증가할 수 있다고 느꼈습니다. 이런 경우 default method로 제공하는 방식에 대해서는 어떻게 생각하시는지도 궁금합니다.
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
NonNullApi를 NullMarked로 대체하라고 합니다.
spring 7 버전에서 부터는 NonNullAPI이 deprecated 되는 것 같습니다.대신 NullMarked로 대체하면 된다고 합니다!
-
미해결Readable Code: 읽기 좋은 코드를 작성하는 사고법
[강의 질문] 메서드 선언부
안녕하세요 우빈님 메서드 선언부 강의 내용 중 궁금한 부분이 있어서 질문 남깁니다. 기존 메서드(checkIfAllCellIsOpened)가셀이 모두 열렸는지 체크게임이 모두 끝났는지 체크위의 두 내용을 나타내지 못하기 때문에 결국 게임이 끝났는지를 체크하는 메서드로 변경되었습니다. (checkIfGameOver)여기서 궁금한점이 1. 의 일은 2. 에 대한 과정이라고 생각하는데 과정을 메서드 이름으로 드러내지 않아도 되는건지요?메서드만 보았을 땐 셀이 모두 열렸는지를 체크하는 것을 알지 못하기 때문에 이것또한 이름으로 드러내야하는지가 궁금합니다. 🙇🏻♂️
-
미해결Readable Code: 읽기 좋은 코드를 작성하는 사고법
[강의 질문] 메서드와 추상화
메서드와 추상화 관련해서 질문이 있습니다. 메서드가 2가지 이상의 일을 하면 구체적인 내용의 유추가 어렵기 때문에 더 작은 단위의 메서드로 쪼개고 더 큰 맥락 안에서 포괄적인 의미를 담는 메서드 명 변경하라고 말씀 주셨는데 더 작은 단위의 메서드로 쪼개지 않고 메서드 명만 포괄적인 의미를 잘 담아서 표현하게 되도 괜찮은 걸까요?즉, 아래와 같이 메서드 단위로 분리 하지 않아도 메서드 명만 하나의 주제를 나타내면 되지 않을까 싶어서 질문 드립니다. void 산책하면서 돈쓰기() { 우빈이는 산책하다가 은행해서 현금을 인출했다. 서점가는길에 아이스크림을 사먹었다. 남은돈으로 서점에서 가서 책을 구입하였다. }
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
39. 문서와 코드 다듬기 updateInfo 테스트 질문 있습니다.
MemberDetail 테이블의 UK_MEMBER_DETAIL_PROFILE_ADDRESS 유니크 제약 조건과 관련해서 질문이 있습니다.39장 강의 마지막 부분에서, 해당 프로파일 주소(profile_address)를 빈 문자열로 바꿔 삭제할 수 있는 부분 테스트를 추가 하셨는데, 그런데 이렇게 되면 여러 사용자가 프로필 주소를 빈값으로 변경 할 경우 제약 조건에 충돌이 발생할 수 있을 것 같습니다.profile_address 값을 빈값으로 설정할 수 없도록 테스트를 조정하는게 더 맞아 보이는데 제가 생각한게 맞을까요?
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
Repository Adapter 설계에 대해 피드백을 부탁드립니다
안녕하세요 토비님!!강의를 완강하고 제 프로젝트를 리팩토링하면서 피드백받고싶은점이 생겨 질문글을 올립니다.Repository Port를 기술에 종속시키지 않기 위해 Adapter에서 JPA, MyBatis, QueryDSL을 조합하는 구조를 선택했는데, 이 설계 방향이 적절한지 조언을 구하고 싶습니다.현재 구조 core/ └── domain/ └── application/ └── required/ ← Port 인터페이스 └── ~Repository adapter/ └── persistence/ ├── ~RepositoryAdapter ← Port 구현체 ├── ~JpaRepository ← Spring Data JPA └── ~MybatisMapper ← Mybatis 매퍼 인터페이스 의존 관계 [Service] → [Repository] ←impl― [RepositoryAdapter] → [JpaRepository] → [MybatisMapper] → [JPAQueryFactory] (core) (core) (adapter) (adapter) 예시@Repository @RequiredArgsConstructor public class ItemRepositoryAdapter implements ItemRepository { private final ItemJpaRepository itemJpaRepository; private final ItemMybatisMapper itemMybatisMapper; @Override public List<Item> findBySearchRequest(ItemSearchRequest request) { return itemMybatisMapper.findBySearchRequest(request) .stream() .map(Item::from) .toList(); } @Override public List<Item> saveAll(List<Item> items) { return itemJpaRepository.saveAll(items); } } @Repository @RequiredArgsConstructor public class AuctionRepositoryAdapter implements AuctionRepository { private final JPAQueryFactory jpaQueryFactory; private final AuctionJpaRepository auctionJpaRepository; @Override public void deleteAllByRegionAndRealmId(RegionType region, Long realmId) { QAuction qAuction = QAuction.auction; BooleanBuilder filter = new BooleanBuilder(); filter.and(qAuction.region.eq(region)); if (realmId == null) { filter.and(qAuction.realmId.isNull()); } else { filter.and(qAuction.realmId.eq(realmId)); } jpaQueryFactory.delete(qAuction) .where(filter) .execute(); } @Override public int saveAll(List<Auction> auctions) { if (auctions.isEmpty()) return 0; return auctionJpaRepository.saveAll(auctions).size(); } } 이 구조를 선택한 이유동적 쿼리, 벌크 연산 등 JPA만으로 해결하기 어려운 케이스가 있어 MyBatis와 QueryDSL을 병행 사용하고 있습니다.일반적인 방식인 Port 인터페이스가 Spring Data JPA Repository를 상속하는 구조를 채택하지 않은 이유:MyBatis나 QueryDSL 기반 구현체를 만들 수 없음CustomRepository 인터페이스를 별도로 만들어야 하는 복잡도 증가현재 방식의 장점:Port 인터페이스가 순수 Java 인터페이스로 유지됨RepositoryAdapter에서 상황에 맞는 기술을 자유롭게 조합 가능추가 인터페이스 없이 단순한 구조 유지저는 현재 구조가 의존 관계도 외부에서 내부로 향하고 테스트도 쉬워서 괜찮다고 생각하는데 토비님의 생각도 듣고싶습니다!! 좋은 강의 감사합니다!!
-
해결됨토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
헥사고날 part2 강의 출시 예정일 문의 드립니다.
Part1 강의 너무 재미있게 봐서 Part2강의가 너무 기다려집니다. Part2 강의 출시가 언제쯤 되는지 혹시 계획이 있으신지 궁금합니다. 항상 좋은 강의해주셔서 감사합니다.
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
PT 문의사항
안녕하세요! 수업 잘 듣고 있습니다.PT하실때 쓰신 툴이 무엇일까요?너무 깔끔하고 좋은 것 같습니다.
-
미해결[파이썬 게임개발] 초보자도 따라하는 지뢰찾기 만들기
입문자 입장에서는
전 강의에서 그러던데애초부터 모듈로 작성하면 안 헷갈린데main 작성 하고 그걸 또 중간에 모듈로 빼 버리면 입문자 입장에서 헷갈림.즉흥적으로 하는 느낌이 들음,. 전 강의에서부터최소한 정리를 하고 입문자 눈높이에서 설명해주면 좋겠음.실전에서는 강사의 방식이 맞을지 몰라도 배우는 사람입장에서는 왔다갔다하니 헷갈림.
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
안녕하세요 혹시 프론트 코드 제공받을 수 있을까요?
안녕하세요 강의 잘 보고있습니다.다름이 아니라 프론트쪽 코드가 궁금해서 리액트 코드좀 받고싶은데 받을 수 있을까요?메일:ad0362320@naver.com 입니다. 항상 감사드립니다!!
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
실행이 안되네요
Execution failed for task ':compileKotlin'.> Error while evaluating property 'filteredArgumentsMap' of task ':compileKotlin' > Could not resolve all files for configuration ':compileClasspath'. > Could not find org.jetbrains.kotlin:stdlib-jdk8:1.6.21. Required by: project :Possible solution: - Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html 위와 같은 에러가 뜨는데아래 잘 바꿨거든요? plugins { id 'org.springframework.boot' version '2.7.6' id 'io.spring.dependency-management' version '1.0.12.RELEASE' id 'java' id 'org.jetbrains.kotlin.jvm' version '1.6.21' } group = 'com.example' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.jetbrains.kotlin:stdlib-jdk8' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() } compileKotlin{ kotlinOptions{ jvmTarget="11" } } compileTestKotlin{ kotlinOptions{ jvmTarget="11" } }왜안될까요
-
미해결실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
프론트 영역 보는법
안녕하세요 이거 프론트 부분은 다 해서 주시는데프론트 영역은 어떻게 보는지 알 수 있을까요?
-
미해결생성형 AI를 활용한 세상에서 제일 쉬운 파이썬 개발 클래스
VS code 사용법 문의
좋은 강의 감사합니다. [onc88]강의 내용 중 삼각형 아이콘을 눌러 실행 화면 만들 때 아래 같이 구성 안되고 아래 : C:\Inflearn\source_stage\01_start_python_ai> python test.py & C:/Python111/python.exe..... 아래2 같이 나와서 삼각형 아이콘을 눌러도 동작 안됩니다. (python test.py 실행해야 동작) 아래2:C:\Inflearn\source_stage\01_start_python_ai 다음 & C:/Python111/python.exe.....을 추가하려면 어떻게 해야하나요?
-
미해결Readable Code: 읽기 좋은 코드를 작성하는 사고법
DIP 개념에 대한 질문입니다.
DIP라는 개념을 상위수준의 모듈에서 하위수준을 의존해서는 안된다는 정의에 대한 설명에서 질문드립니다. 이때 의존성의 순방향이란, 자바로 따지면 상위 객체에서 하위 객체를 생성하여 활용하는 정도로 이해했습니다. 이떄 저수준의 모듈이 변경된다는게 메소드 단위의 개념인지 객체의 구현체 단위의 개념인지 정확히 모르겠습니다. 메소드라면, 저수준의 모듈이 변경된다는게 사실 메소드 시그니처가 변경되면 문제가 되겠습니다만, 안에 구현이 바뀐다고 해서 상위 모듈에서 하위 모듈의 메소드를 호출할 때 영향이 간다는 생각이 들지 않았습니다.구현체라면, 런타임 시점에 구현체가 결정되고/ 실행되기 때문에 이를 담는 추상 객체로 코딩된 고수준의 모듈에는 변화가 없다고보면 되는건지요..? 결국 주입되는 구현체의 변경에 유연하다는 정도로 보면될까요?
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
초기 어플리케이션 구동 시 compose.yml 파싱 오류
spring-boot 버전 4.0.0 으로 프로젝트를 생성하면 어플리케이션 구동 시 아래와 같은 오류가 발생합니다. (현재 2025-12-08)3.x 버전으로 내리면 발생하지 않으니 참고해주세요.2025-12-08T18:40:05.881+09:00 INFO 2496 --- [splearn] [ main] .s.b.d.c.l.DockerComposeLifecycleManager : Using Docker Compose file /Users/coffeenjava/work/study/splearn/compose.yaml2025-12-08T18:40:06.285+09:00 ERROR 2496 --- [splearn] [ main] o.s.boot.SpringApplication : Application run failedtools.jackson.core.exc.StreamReadException: Unexpected character ('\' (code 92)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')at [Source: REDACTED StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); byte offset: #UNKNOWN]at tools.jackson.core.JsonParser._constructReadException(JsonParser.java:1800) ~[jackson-core-3.0.2.jar:3.0.2]
-
미해결만들면서 배우는 리액트: 컴포넌트 설계와 리팩토링
로컬스토리지 에러
3(index):1 Uncaught (in promise) Error: Access to storage is not allowed from this context. 이렇게 뜨는데요.또 로컬 스토리지 보면들어가긴 하거든요? 왜그럴까요
-
미해결토비의 클린 스프링 - 도메인 모델 패턴과 헥사고날 아키텍처 Part 1
애플리케이션의 JPA 리턴과 도메인 모델
안녕하세요 토비님 강의 잘 수강하고 있습니다. 좋은 강의 감사드립니다. 저는 JPA엔티티를 도메인 모델로 사용하고 애플리케이션에서 이를 리턴하고 있습니다.그런데 새로운 팀원 한명이 이렇게 이야기하더군요이전에 마이바티스를 사용하다가 JPA가 나온거처럼 이를 대체하려면 코드변화가 필요할 것 입니다 사실 이것도 저는 맞는 말이라고 생각합니다. JPA 엔티티를 참조하는 모든 부분을 수정이 필요할 것 같습니다. 그럼에도 불구하고, 트레이드오프 관점에서 보면 현재 잘 사용하는 JPA엔티티를 그대로 사용하는게 더 효과적이라고 생각합니다. 여기서 궁금한게, 이렇게 새로운 데이터접근 기술이 나오게 되는 것까지 고려하는게 맞을까요? 어떠한 논리를 펼쳐서 JPA를 그대로 의존하는게 좋다고 이야기하는게 더 설득력이 있을까요?