김영한
@yh
수강생
585,353
수강평
40,857
강의 평점
5.0
교육자
전: 우아한형제들 기술이사, 카카오, SK플래닛
진짜 실무에 필요한 제대로 된 개발자가 될 수 있도록, 교육하는 것이 저의 목표입니다.
저의 개발 인생 이야기
EO 인터뷰 영상
개발바닥 - 시골 청년 개발왕 되다
취업과 이직에 대한 고민 해결
강의
로드맵
전체 4수강평
- 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
- 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
- 스프링 부트 - 핵심 원리와 활용
게시글
질문&답변
강의 자료에 사소한 오타가 있습니다.
i2mi님 고맙습니다^^!다음 버전에 패치할게요.
- 0
- 2
- 11
질문&답변
오탈자 - @Transactional
장태근님 감사합니다^^!다음 버전에 패치할게요!
- 0
- 1
- 20
질문&답변
RequestHandler 버전 간 process() 파라미터 차이 질문
안녕하세요. sjahn님둘다 필요한 방법입니다 🙂진행중에 각각 필요한 방식이 달라지기 때문에 중간에 변화가 되었습니다. 1. 멤버 변수 방식 (상태를 가지는 객체 - Stateful)적절한 상황: 객체가 고유한 데이터(상태)를 스스로 관리하고, 그 데이터의 변화를 추적해야 할 때. 2. 파라미터 전달 방식 (상태가 없는 객체 - Stateless)적절한 상황: 객체가 스스로 데이터를 기억할 필요 없이, 외부에서 재료를 받아 가공이나 흐름 제어 같은 '행위(로직)'만 전담할 때. 감사합니다.
- 0
- 2
- 45
질문&답변
교재 p.31 실행순서 오류?
안녕하세요. swdevelop24님생각하신 내용이 맞습니다 🙂데이터베이스 SQL의 실행 순서는 논리적 실행 순서와 물리적 실행 순서가 있습니다.논리적 실행 순서는 사람이 이해하기 쉬운 순서이고, 물리적 실행 순서는 데이터베이스가 내부에서 최적화하는 실제 순서입니다.처음 데이터베이스를 접하는 분들 입장에서는 내부 최적화 구조까지 이해하면 데이터베이스가 정말 어려워지기 때문에 지금은 사람이 이해하기 쉬운 논리적인 순서를 말씀드린거에요^^이후에 기본편에 들어가면 데이터베이스가 내부 구조까지 모두 이해하실 수 있을거에요 🙂감사합니다.
- 0
- 2
- 70
질문&답변
통계 데이터 수정 질문
안녕하세요. learnlearn님비즈니스 상황을 자세히는 모르겠지만, 특정 유저와 날짜 단위로 배치가 이루어지고, 해당 배치가 크게 부담이 되는 상황이 아니라면, 수정한 사용자와 수정 일자만 모아두고, 해당 사용자의 해당 수정 일자의 배치만 멱등하게 돌아가도록 하면 깔끔하게 진행될 것 같아요.실시간 증분은 속도는 빠를 수 있지만 멱등성이 깨질 수 있기 때문에 더 많은 고민이 필요합니다.감사합니다.
- 0
- 2
- 42
질문&답변
공통 코드에서 Redis Pub/Sub은 최근 실무에서 쓰이진 않나요?
안녕하세요. kekim님AI 인턴이 잘 답변해주었는데요. 조금 더 보충하자면이 부분은 실무에서 겪고 있는 상황에 따라 다릅니다.비즈니스 로직상 정확한 갱신이 너무 중요하다면 Redis Pub/Sub은 고민하신 것 처럼 리스크가 있습니다.다만 현재 팀에서 Redis를 잘 사용하고 있고, 비즈니스 로직상 만약에 갱신에 일부 실패해도 허용 가능한 범위의 리스크라면 Redis Pub/Sub을 사용해도 괜찮습니다.감사합니다.
- 0
- 2
- 96
질문&답변
캐시무효화시 그냥 no-store만 넣어되지 않나요?
안녕하세요. 캐내기님다음을 참고해주세요 🙂https://inf.run/ucXRb감사합니다.
- 0
- 2
- 47
질문&답변
제네릭 타입 매개변수 제한과 관련한 문의입니다.
안녕하세요. 서규환님AnimalHospitalV3처럼 상위 타입을 타입 인자로 직접 지정하면, Dog과 Cat이 섞여 들어와도 컴파일러가 잡아주지 못하는 것이 맞습니다.결론부터 말씀드리면, 이것은 제네릭의 한계가 아니라 사용하는 쪽의 책임입니다.제네릭의 설계 의도를 먼저 생각해보면제네릭은 "사용하는 시점에 타입을 구체적으로 결정하라"는 것이 핵심입니다. 즉, 다음과 같이 사용하는 것이 올바른 사용법입니다.AnimalHospitalV3 dogHospital = new AnimalHospitalV3(); AnimalHospitalV3 catHospital = new AnimalHospitalV3();AnimalHospitalV3로 선언하는 것은, 개발자가 스스로 "나는 모든 Animal을 다 받겠다"고 선언한 것입니다. 이것은 제네릭을 쓰면서 일부러 다형성 방식으로 돌아간 것이기 때문에, 그에 따르는 책임(캐스팅 등)도 개발자가 지게 됩니다. 그러면 실무에서 실수를 줄이는 방법은 무엇이 있을까요?1. 코드 리뷰와 컨벤션으로 방지실무에서 가장 현실적인 방법입니다. "타입 인자로 상위 타입을 직접 지정하지 말 것"이라는 팀 컨벤션을 정하는 것입니다. 사실 대부분의 경우 로 지정할 이유가 없습니다. 구체적인 타입으로 지정하는 것이 제네릭의 올바른 활용법이니까요.2. 와일드카드를 활용한 읽기 전용 제한만약 여러 Animal 타입을 함께 다뤄야 하는 상황이라면, 와일드카드를 활용할 수 있습니다. 이 부분은 뒤에서 학습하게 됩니다.// 데이터를 꺼내서 읽기만 하는 경우 void printAnimal(AnimalHospitalV3 hospital) { // hospital.set(new Dog(...)); // 컴파일 오류! 넣을 수 없음 Animal animal = hospital.get(); // 꺼내는 것만 가능 }이렇게 하면 꺼내서 읽는 것은 가능하지만, 잘못된 타입을 넣는 실수는 컴파일 시점에 막을 수 있습니다.3. 근본적인 관점자바의 타입 시스템에서 AnimalHospitalV3이라는 선언 자체를 금지하는 방법은 없습니다. 질문에서 언급하신 것처럼 Animal을 추상 클래스나 인터페이스로 만들어도, 타입 인자로 지정하는 것까지 막지는 못합니다.하지만 이것은 Object obj = new Dog()와 본질적으로 같은 문제입니다. 자바에서 상위 타입으로 참조하는 것 자체를 금지할 수는 없고, 그렇게 하는 순간 발생하는 책임은 개발자에게 있는 것입니다.정리하면제네릭의 가치는 , 처럼 구체적인 타입을 지정했을 때 빛을 발합니다. 로 지정하는 것은 제네릭의 장점을 스스로 포기하는 것이므로, "구체적인 타입을 지정해서 사용하는 것이 원칙"이라고 이해하시면 됩니다. 실무에서는 코드 리뷰를 통해 이런 부분을 잡아내고, 필요한 경우 와일드카드를 활용하는 것이 가장 현실적인 방법입니다. 하지만 약간의 대안도 있습니다. 1. 구체적인 타입 인자 사용 원칙 (가장 기본적이고 권장되는 방법)제네릭의 본래 도입 목적은 사용할 타입을 명확히 지정하여 컴파일 시점에 오류를 잡는 것입니다. 따라서 객체를 생성할 때 AnimalHospitalV3 대신, AnimalHospitalV3, AnimalHospitalV3과 같이 명확한 하위 타입을 지정해서 생성하는 것을 기본 원칙으로 삼아야 합니다. 이렇게 구체 타입을 명시하면, 개 병원에 고양이를 넣으려고 할 때 컴파일러가 완벽하게 오류를 잡아냅니다.2. 정적 팩토리 메서드를 활용한 객체 생성 제한클라이언트 개발자가 실수로 을 넣어서 인스턴스를 생성하는 것을 아예 막고 싶다면, 생성자를 막고 정적 팩토리 메서드를 제공하는 방식을 사용할 수 있습니다.public class AnimalHospitalV3 { // 1. 외부에서 직접 생성을 막음 private AnimalHospitalV3() {} // 2. 정적 팩토리 메서드로 특정 구체 타입만 생성하도록 유도 public static AnimalHospitalV3 createDogHospital() { return new AnimalHospitalV3(); } public static AnimalHospitalV3 createCatHospital() { return new AnimalHospitalV3(); } // ... } 이렇게 설계하면 개발자가 무심코 new AnimalHospitalV3()을 호출하는 것을 구조적으로 차단하고, 허용된 구체 타입의 병원만 생성하도록 강제할 수 있습니다. 감사합니다.
- 0
- 3
- 55
질문&답변
AspectV1 예제를 @Configuration 수동 등록으로도 가능한가요?
안녕하세요. 이상우님수동 빈 등록을 사용해도 정상적으로 작동해야 합니다.확인을 하려면 전체 코드를 봐야할 것 같아요.실제 동작하는 전체 프로젝트를ZIP파일로 압축해서 구글 드라이브로 공유해서 링크를 남겨주세요.구글 드라이브 업로드 방법은 다음을 참고해주세요.https://bit.ly/3fX6ygx주의: 업로드시 링크에 있는 권한 문제 꼭 확인해주세요추가로 다음 내용도 코멘트 부탁드립니다.1. 문제 영역을 실행할 수 있는 방법2. 문제가 어떻게 나타나는지에 대한 상세한 설명 (오류 화면, 오류 로그 포함)링크: 공식 서포터즈링크: 자주하는 질문감사합니다.
- 0
- 2
- 61
질문&답변
모니터와 synchronized, ReentrantLock, 원자적연산 CAS관련해서 추가적으로 더 깊게 공부했는데 제가 이해한 것이 맞나요??
안녕하세요. 정재익님다른 부분은 맞는데요. 다음 부분은 정정이 필요합니다.synchronized는 자바가 구현한 모니터인데 조건변수의 추가가 불가능해서 생산자 소비자 문제를 해결할 수 없습니다.이 부분은 반은 맞고 반은 틀렸습니다. synchronized 역시 자바의 모든 객체가 기본적으로 가지고 있는 모니터 락과 '스레드 대기 집합(wait set)'이라는 조건 변수를 사용합니다. 따라서 Object.wait()와 Object.notify()를 사용하면 생산자 소비자 문제를 해결할 수는 있습니다.진짜 문제는 '조건 변수의 추가가 불가능하다'는 점입니다. synchronized는 내부적으로 단 1개의 스레드 대기 집합만 가집니다. 따라서 생산자 스레드와 소비자 스레드가 같은 대기 공간에 섞여서 대기하게 됩니다. 이로 인해 생산자가 데이터를 만든 후 소비자를 깨우고 싶은데 실수로 대기 중인 다른 생산자를 깨우거나(비효율), 반대로 소비자가 다른 소비자를 깨우는 비효율적인 문제가 발생합니다.(결과적으로 로직은 동작하지만, 헛도는 스레드가 생겨 비효율적입니다.)감사합니다 🙂
- 0
- 1
- 69











