소개
- (현) 카카오 백엔드 엔지니어
- (수상) 🏆 공개 SW 개발자 대회 [2020 일반부문 / 금상_정보통신산업진흥원장상]
현재 카카오에서 일하고 있고, 만드는 것을 좋아해서, 퇴근 후에도 항상 무언가를 개발하고 있습니다.
"거인의 어깨 위에 선 난쟁이"라는 말이 있습니다. 저 역시 한낱 작은 난쟁이일 뿐이지만, 올라탄 거인의 성장에 도움이 될 수 있도록 지식의 대물림을 위해 노력하고 있습니다. 다수의 주니어 개발자분들을 멘토링 한 경험이 있어서 여러분의 성장을 도와줄 수 있을 거예요.
깃허브 > https://github.com/kok202
블로그 > https://kok202.tistory.com
강의
전체 2수강평
- Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
- Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
- Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
- Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
게시글
질문&답변
2024.01.30
혹시 git 플러그인 아시는 분
안녕하세요. 어떤 기능을 물어보시는지 정확히 잘 이해가 안 되는데요. 혹시 아래 기능을 말하시는 게 맞으실까요?(사진)이는 IntelliJ 기본 내장 기능입니다. 커밋 앞 > Run SpotBugs analysis, 커밋 앞 > Scan with Checkstyle 정도만 IntelliJ 추가 플러그인을 설치해서 표기되는 내용이고요. (각각 SpotBugs, Checkstyle 플러그인입니다.)혹시 IntelliJ Ultimate 전용 기능인가 싶어 Community에서는 안보이나도 확인해 봤습니다. 그리고 Ultimate, Community 관계없이 잘 보이는 것도 확인했습니다.IntelliJ에서 Commit 방식을 탭 버전으로 하고 있는 것은 아닌가요? modal 버전을 사용하도록 설정 변경해 보는 것은 어떤지요? (여기: https://engineerinsight.tistory.com/90) 참고하면 좋을 것 같습니다.번외 참고: https://intellij-support.jetbrains.com/hc/en-us/community/posts/360007373539-The-new-Commit-tab
- 0
- 1
- 365
질문&답변
2024.01.30
패키지 의존성을 확인해보는법?
사용해 본 적이 없기에 툴의 존재는 잘 모르겠네요. 알고 있었다면 저도 강의에서 소개했을 것 같습니다.😭 저도 매번 찾아볼 때마다 원하는 수준으로 나오는 걸 못 봐서, 그냥 일일이 눈으로 확인하고 있었습니다.그래서 질문 주셨기에 마침 기회다 싶어서 다시 찾아봤는데요. 그나마 가장 괜찮은 방법은 IntelliJ Ultimate 버전의 분석 기능이 아닌가 싶습니다. 다음과 같은 분석 기능을 제공해 주네요.(사진)각 기능 모두 패키지, 클래스 수준까지 의존성을 확인할 수 있습니다.참고.1 https://jaehoney.tistory.com/311참고.2 https://v0o0v.tistory.com/4그런데 저의 니즈도 다이어그램으로 보고 싶은 것이라, 솔직히 위 기능이 얼마나 쓸모 있는지는 잘 모르겠습니다.
- 0
- 2
- 1.1K
질문&답변
2024.01.30
도메인 객체와 영속성 객체를 구분하게 되면
안녕하세요. 근래에 책을 집필할 기회가 생겨 그쪽에 힘을 실어주다 보니 다른 일에 신경 쓰지 못했습니다. 답변이 늦어 죄송합니다. 다만 해당 강의는 공식적으로 질의응답을 제공하지 않는 강의였다는 점을 이유로 늦어진 부분에 대해 양해 부탁드립니다.김남호 님이 좋은 답변해 주신 것 같네요. 감사합니다.이야기하신 대로 도메인 객체와 영속성 객체를 구분하면 JPA에서 제공해 주는 기능들을 사용하지 못합니다. 그런데 이것이 헥사고날 아키텍처와 의존성 역전 원칙이 추구하는 방향입니다. 두 이론 모두 시스템이 특정 라이브러리에 종속되지 않으려면 어떻게 해야 하는지를 이야기하고 있습니다.이와 관련해서는 이전에 비슷한 답변을 한 적이 있기에 링크로 대체하겠습니다.https://www.inflearn.com/questions/947209/jpa의-더티체킹-사용에-대해서https://www.inflearn.com/questions/945855/comment/280701https://www.inflearn.com/questions/978220더불어 양방향 매핑은 사실상 순환 패턴으로 안티 패턴입니다. 근본적으론 양방향 매핑을 안 만드는 것이 제일 좋습니다. 단방향 매핑으로만 객체 관계를 정의하면 생각보다 생성 수정이 쉽습니다.
- 0
- 3
- 1.4K
질문&답변
2024.01.30
UUID, Random 등 자주 사용하는 의존성의 경우
안녕하세요. 근래에 책을 집필할 기회가 생겨 그쪽에 힘을 실어주다 보니 다른 일에 신경 쓰지 못했습니다. 답변이 늦어 죄송합니다. 다만 해당 강의는 공식적으로 질의응답을 제공하지 않는 강의였다는 점을 이유로 늦어진 부분에 대해 양해 부탁드립니다.공통으로 사용하는 유틸 클래스들을 하나의 패키지에 모아 관리하는지가 궁금한 것으로 보이는데 맞으실지요? 네, 그렇게 사용합니다. util 패키지가 생기는 것 자체는 전혀 이상한 게 아닙니다. 스프링 프레임워크에서도 util 패키지 사용합니다. (참조: https://github.com/spring-projects/spring-framework/tree/main/spring-core/src/main/java/org/springframework/util) 그리고 ClockHolder, UuidHolder는 충분히 util 패키지에서 관리할 만한 인터페이스라 생각합니다.다만 그렇다고 모든 프로젝트에서 항상 util 패키지를 만들어 사용하는 것은 아닙니다. 이는 상황에 따라 다릅니다. util 패키지를 만드는 경우, 도메인으로 엮여야 할 비즈니스 로직들이 종종 클래스 이름에 util이라는 이름을 달고 util 패키지로 모이는 경우가 생깁니다. 그래서 프로젝트 별로 util 패키지 자체를 만드는 것을 선호하지 않기도 합니다.그러니 ClockHolder, UuidHolder의 위치는 common.domain에 들어가도 되고 util에 들어가도 된다 생각합니다. 사실 클래스의 패키지 위치나 이름 자체는 그렇게 중요한 문제가 아닙니다.원하시는 답변이 됐는지 잘 모르겠습니다. 답변이 도움 됐길 바랍니다. 감사합니다.+) 음… 그런데 제 생각엔 본질적으로 이 질문은 실제로 ‘어떻게 사용하는지가 궁금하다’기보다, 개발에 대한 확신이 없어서 긴가민가하고 있는 것에 기인한 게 아닐까 싶습니다. 그래서 답을 원하는 것 같기도 하고요…? (어차피 개발에 정답은 정해져 있지 않습니다. 확신과 근거만 있으면 됩니다. 만들어 보고, 막상 만들어 봤더니 별로다 싶으면 수정하면 되죠.) 그러니 그냥 마음내키는 대로 개발해 보는 게 좋지 않을까 싶네요!
- 0
- 2
- 621
질문&답변
2024.01.30
n+1질문입니다!
안녕하세요. 근래에 책을 집필할 기회가 생겨 그쪽에 힘을 실어주다 보니 다른 일에 신경 쓰지 못했습니다. 답변이 늦어 죄송합니다. 다만 해당 강의는 공식적으로 질의응답을 제공하지 않는 강의였다는 점을 이유로 늦어진 부분에 대해 양해 부탁드립니다.Member ↔ Team 관계에서 팀과 팀원을 나타내는 정보가 아래와 같다고 가정합시다.@Getter @Builder class Team { private long id; private String name; } @Getter @Builder class Member { private long id; private String name; private Team myTeam; } @Data @NoArgsConstructor @Entity(name = "team") class TeamJpaEntity { @Id private String id; @Column private String name; public Team toModel() { ... } } @Data @NoArgsConstructor @Entity(name = "member") class MemberJpaEntity { @Id private String id; @Column private String name; @ManyToOne @JoinColumn(name = "my_team_id") private TeamJpaEntity myTeam; public Member toModel() { ... } } 이때 팀 정보와 팀원 정보를 같이 있는 도메인 객체인 TeamWithMembers 라는 도메인이 있다 가정합시다. TeamWithMembers은 다음과 같습니다.class TeamWithMembers { private long id; private String name; private List members; } 그리고 TeamWtihMembers의 JpaEntity는 없습니다. 그러면 이때 TeamWithMember를 어떻게 만들 수 있을지 고민해 봅시다.방법.1 서비스에서 Team 정보, Member 정보를 Repository로부터 모두 불러와 TeamWithMembers 도메인을 만들어 사용한다.이는 즉 아래와 같은 코드를 만들겠다는 의미입니다.class MyService { // 의존성 주입되는 코드 생략 public void doSomething() { Team team = teamRepository.getById(teamId); List members = memberRepository.findByTeamId(teamId); TeamWithMember teamWithMember = TeamWithMember.builder() .id(team.getId()) .name(team.getName()) .members(members) .build(); // ... } } 이 방법을 사용하면 트랜잭션 스크립트 같은 코드가 만들어질 수 있습니다. 그것 외에는 특별히 문제가 될 만한 점은 보이지 않습니다. 이러한 역할을 수행하는 것이 서비스의 역할인 것인지는 약간 의문이 들긴 하나 그렇다고 또 완전히 틀린 역할은 아닙니다. 추가로 염려되는 점이라면 코드를 이렇게 작성하다 보면 결국 TeamWithMembers를 만들어주는 역할을 전문적으로 하는 서비스가 만들어 질 수 있다는 것입니다.방법.2 리포지토리에서 Team 정보, Member 정보를 Repository로부터 모두 불러와 TeamWithMembers 도메인을 만들어 사용한다.이는 즉 아래와 같은 코드를 만들겠다는 의미입니다.class TeamWithMembersRepositoryImpl implements TeamWithMembersRepository { // 의존성 주입되는 코드 생략 public TeamWithMembers getById(long teamId) { Team team = teamJpaRepository.getById(teamId); List members = memberJpaRepository.findByTeamId(teamId); return TeamWithMember.builder() .id(team.getId()) .name(team.getName()) .members(members) .build(); } } 크게 문제없어 보입니다.종합하면 이야기해 주신 상황은 Repository의 역할로 보입니다. 왜냐하면 Repository의 역할은 도메인 데이터를 저장하고 불러오는 것인데, TeamWithMembersRepositoryImpl은 그 역할에 정확히 부합한 일을 수행하고 있기 때문입니다.사실 이 문제는 의존성 역전만 제대로 돼있다면 방법.1로 개발하던 방법.2로 개발하던 크게 상관이 없는 문제입니다. 그래서 개발자마다 해석이 다를 수 있고 저는 방법.2가 맞다 생각하지만, 누군가는 방법.1이 맞다 생각할 수도 있습니다.헷갈린다면 어느날 갑자기 Jpa가 갑자기 사라진다고 생각해 보길 바랍니다. 그리고 “Jpa가 아닌 JdbcTemplate으로 대체해야 할 때 Domain, Service 코드를 안 건드려도 되는가?”를 고민해 보시길 바랍니다. 그리고 이 상황에서 방법.1이든 방법.2든 모두 안전합니다.답변에 도움이 됐길 바랍니다.
- 0
- 2
- 702