묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨오브젝트 - 설계 원칙편
8-5 책임 분리를 통한 중복 코드 제거 과정에서 특정 조합은 불가능할 때
안녕하세요!AbstractReader로부터 파싱에 대한 책임을 분리하여 Parser라는 클래스를 새로 생성하는 내용 잘 들었습니다!여기서 궁금한 것이 생겨 질문 남깁니다..!DatabaseReader, RedisReader, FileReader / CsvParser, JsonParser, XmlParser 구성은 총 9가지의 경우의 수가 나올 수 있을 것 같은데요만약 '(DatabaseReader, XmlParser)는 불가능하고 (DatabaseReader, CsvParser)와 (DatabaseReader, JsonParser)가 가능하고,(RedisReader, XmlParser)와 (RedisReader, CsvParser)는 불가능하고 (RedisReader, JsonParser)만 가능하다' 와 같이 특정 조합이 불가능한 경우는 어떻게 컴파일 타임에 가능한 조합으로만 강제할 수 있을지 궁금합니다!
-
미해결실무에 바로 적용하는 프런트엔드 테스트 - 2부. 테스트 심화: 시각적 회귀・E2E 테스트
e2e 테스트 CI , 서버비용
안녕하세요 e2e 테스트는 비용이 많이 들어서 어떻게 관리를 하는지 궁금합니다. - 파이프라인에서 매번 CI 에서 돌리기에는 서버나, 시간이 개발 생산성을 잡아 먹을 것 같은데요. 점점 e2e 테스트가 쌓여 나갈떄 어떤 전략을 취할 수 있는지 궁금해요. GPT로 리서치하니까 보통 2가지를 병행해서 스케줄러 + 온디맨드 실행 같이 관리 한다고 하는데, 실제 현업에서는 어떻게 활용하고 계신지, 제가 리서치한 내용 말고 더 효율적이거나, 추천할만한 전략 , 이외의 고려사항 소개해주실 수 있으면 알려주시면 감사하겠습니다.스케줄 실행 (Nightly/주말 풀스윗)EventBridge → ECS Fargate RunTask(Spot 가능) → Playwright 러너대상: 스테이징(or PR 프리뷰 URL)b. 산출물: 트레이스/비디오/리포트 S3 업로드, Slack에 요약/링크온디맨드 실행 (PR 코멘트/수동 트리거)Bitbucket Pipeline에서 aws ecs run-task 호출(또는 ChatOps 슬래시 커맨드)태그/폴더/샤드 인자 넘김 → 필요한 부분만
-
미해결Pytest와 Nox를 활용한 파이썬 테스트 자동화 완벽 가이드
nox 실행 에러 메세지
챕터 17 nox 테스트 중입니다. 테스트 환경은 윈도우11, 파이썬 3.11버전이고 공유주신 noxfile.py 의 tests 세션을 실행하던 중에 다음 에러가 발생하였습니다. session.install("-e", ".") 실행중에 에러가 난것으로 보이는데 setup.py 나 pyproject.toml 이 없다고 나오는데 공유주신 자료에는 안보여서요.현재 프로젝트 파일 구조는 my_pytest / mycalc/my_pytest / tests /my_pytest / noxfile.pymy_pytest / requirements-dev.txt 로 되어 있습니다.
-
미해결Java/Spring 주니어 개발자를 위한 오답노트
Repository 인터페이스 위치
class Controller, class Service, Interface Repository, class RepositoryImpl, Interface JpaRepository의 그림에서 Interface Repository 가 Persistence 가 아닌 Business 계층으로 분리하신 이유가 궁금합니다!
-
미해결Practical Testing: 실용적인 테스트 가이드
DTO 검증 필드에 대한 테스트 코드 작성은 어디까지?
DTO의 검증 필드마다 테스트코드를 작성하는게 실무에서 일반적인가요? 이렇게 되면 DTO가 커질 수록 DTO 한개당 테스트 함수가 10~11개 이렇게 필드개수 만큼 나오게 될텐데 실제로 모두 테스트코드로 검증하나요?
-
미해결Practical Testing: 실용적인 테스트 가이드
OrderCreateRequest DTO에 대해서 궁금한점
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요!먼저 유사한 질문이 있었는지 검색해 보세요.서로 예의를 지키며 존중하는 문화를 만들어가요. Business Layer 테스트(1)의 13:32초 즈음에서 OrderCreateRequest가 Product의 id값이 아니라 productNumber를 요청 dto로 받았는데 그 이유가 있나요? 저라면 id를 받도록 설계할거같은데 이유가 궁금합니다. 실무에서는 보통 저렇게하나요?
-
해결됨오브젝트 - 설계 원칙편
6-2. 명령과 쿼리 분리 원칙 질문
6-2. 명령 쿼리 분리 원칙으로 부수효과 관리하기에 관해 궁금한 점이 있어 질문드립니다! 명령과 쿼리 분리하기 14:43 ~해당 부분에서 Player의 move 메서드를 canMove라는 쿼리와 move라는 명령으로 분리했는데, 여기서 궁금한 점이 있습니다. Player는 이동 가능 여부에 대해 스스로 판단하고 그 결과에 따라 상태를 스스로 변경하는데, Game의 tryMove에서 성공과 실패에 대해 try-catch 구문을 사용하지 않고 if 분기를 사용하는 이유가 무엇인가요?저는 tryMove에서 canMove 쿼리 호출 없이 move 명령을 호출하고, 성공/실패에 대한 처리는 try-catch에서 예외처리하는 것이 더 간단하다 생각했습니다.이번 강의인 6-2의 Player와 8-2 아이템 이동 로직 개선 강의의 Transfer 객체 둘 다 동일한 구조로 코드가 짜여져있어 if 분기를 사용한 이유가 궁금합니다!현재 구조에서 Player의 move 메서드에 예외를 던지는 if 분기가 없다면 Game이 Player의 이동에 관련된 모든 것을 결정하며 TDA를 위반하는 코드라 생각합니다.그렇다면 if 분기는 TDA를 위반하지 않기 위해 넣은 것인가요? 아니면 Player 와 협력하는 다른 클라이언트가 canMove 호출 없이 move를 호출할 경우를 대비해 넣은 것인가요? 후자라고 생각하기에는 1번 질문처럼 Player가 스스로 판단할텐데 try-catch 대신 if 분기를 넣은게 잘 와닿지 않아 질문드립니다!
-
해결됨오브젝트 - 설계 원칙편
9-1 사소한 강의자료 오류
9-1. 더 많은 요구사항 추가하기강의자료 p.45, 강의영상 9:05 ~WorldMap은 target 으로 사용될 경우에만 Carrier를 치환할 수 있는데, 해당 슬라이드에서만 강의자료의 설명과 X 표시가 잘못된 것 같습니다. 영상에서의 설명은 올바른데 자료 표기만 문제가 있는 것 같아 남깁니다!
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
조회 시 엔티티를 조회하는 것이 아닌QueryDSL을 많이 사용 시 Dto는 어떻게 하나요?
일반적인 JpaRepository를 사용할 경우Entity -> Domain model 객체로 변환하는데보통 상세 조회, 목록 조회 시에는 QueryDSL를 사용하고, 또한 조회 시 Projections을 이용하여 Dto로 반환하는데요. 이 때, 조회된 Dto는 User와 마찬가지로 UserDetail, UserList(목록 Dto 명칭이 마땅히 생각나질 않네요.) 와 같은 도메인 모델을 추가로 만들어서 사용하는 건가요? 위와 같은 질문을 드리는 이유는 만약 User가 Team라는 도메인과 연관 관계가 있을 때 Team 정보를 포함하여 응답할 경우 User 따로 조회, Team 따로 조회 하여 응답 dto로 변환해야 할 것같은데 그럼 성능적인 이슈가 생기지 않을까 해서 질문드립니다. (위 예시는 간단해서 성능적 이슈는 크게 없지만 복잡한 도메인에서는 여러 도메인의 정보를 조회해와야 하기 때문에 충분히 성능적 이슈가 있을걸로 판단됩니다.)
-
해결됨오브젝트 - 설계 원칙편
7-3 상속을 이용한 중복 제거 질문 있습니다!
7-3. 의존성 역전 원칙 - 추상화와 세부사항 13:43~수업을 듣던 도중 추상 클래스를 인터페이스와 함께 사용한 이유가 궁금해 질문드립니다.상속이 코드 재사용을 위해 그다지 좋은 방법이 아니라는(+ 자세한 내용은 뒤에서 더 자세히 살펴봄) 언급을 해주셨지만, 우선 여기서는 왜 이렇게 코드를 짰는지 궁금해 고민한 부분을 여쭤보고자 합니다. 인터페이스와 추상 클래스를 함께 사용하는 이유 1. 협력을 위해 제공하는 메시지를 확인하기 용이하기 때문인가요?해당 강의를 듣고나서 맨 처음 들었던 생각은, "추상 클래스로만 추상화를 한 뒤, 상위 수준 객체가 인터페이스 대신 추상 클래스를 의존하면 안될까?" 였습니다. 추상클래스를 사용하더라도 read()만 public이고 readLines()나 parse() 는 각각 private, protected 이므로 외부에 노출되지 않아서 괜찮지 않을까 생각했습니다.더 고민해 보았는데, 인터페이스를 사용한다면 코드를 유지보수하는 과정에서 다음과 같은 이점을 얻을 수 있어서 그런가? 라는 생각이 들어 질문드립니다. 상위 수준의 객체가 인터페이스에 의존하면 역할을 한 눈에 파악하기 쉽다.Reader 는 read()라는 메서드 시그니처로 "특정 데이터소스로부터 읽어오는 작업"을 수행한다. 라는 것을 인터페이스를 통해 명시한다. 즉, "명세" 역할을 한다.이는 유지보수 과정에서 해당 인터페이스만 읽고 구현체가 제공하는(또는 해야하는) 기능(public 메서드)들을 확인하기 용이하다. 즉, 역할을 한 눈에 파악하기 쉽다. 추상 클래스에 의존하면 역할을 한 눈에 파악하기 어렵다.AbstractReader는 메서드 시그니처 뿐만 아니라 중복 로직의 경우 구현 내용까지 포함하고 있고, 여러 메서드들 중 외부에서 협력하기 위해 pubilc으로 노출시켜 제공하는 기능을 한 눈에 파악하기 어렵다.위 두 가지 내용이 인터페이스를 추상클래스와 함께 사용하는 이유가 될 수 있을까요? 2. 두 public 메서드 중 하나는 중복 로직, 하나는 각 구현체마다 다르게 구현하는 경우에도 인터페이스와 추상클래스를 함께 사용하는 것이 좋을까요?1번에서 인터페이스와 추상클래스를 함께 사용한 이유로 언급했던 "역할을 한 눈에 파악하기 쉽다"는 장점이 있다면, 두 메서드 모두 public일 때에도 추상클래스로만 구현하기 보다는 인터페이스와 추상클래스를 함께 사용하는 것이 좋을까요? 2번 질문은 예시 코드를 드리자면 Spring Boot 개발환경에서 작업한 코드로 CaptchaHashProcessor 인터페이스에는 public 메서드인 hash() , verify() 두 메서드가 있습니다. 해당 인터페이스를 구현한 두 구현체에서 verify() 메서드가 중복되는 상황입니다. 기존 코드두 public 메서드를 제공하는 인터페이스public interface CaptchaHashProcessor { HashResult hash(Long captchaId); Long verify(String hashedCode, Long userId); }구현체 1 - hash는 다르게 구현하나 verify는 구현체 2와 내용 동일public class RandomCaptchaHashProcessor implements CaptchaHashProcessor { private static final SecureRandom RANDOM = new SecureRandom(); private final Encryption encryption; private final CaptchaLogPort captchaLogPort; private final EncryptionProperties properties; @Override public HashResult hash(Long captchaId) { // 구현체마다 다름... } @Override public Long verify(String encryptedCode, Long userId) { // 중복 로직 ... } }구현체 2- hash는 다르게 구현하나 verify는 구현체 1과 내용 동일public class FixedCaptchaHashProcessor implements CaptchaHashProcessor { private static final String FIXED_IV = Base64.getEncoder().encodeToString(new byte[16]); private final Encryption encryption; private final CaptchaLogPort captchaLogPort; @Override public HashResult hash(Long captchaId) { // 구현체마다 다름... } @Override public Long verify(String hashedCode, Long userId) { // 중복 로직 ... } } 추상클래스 사용여기서 추상클래스로 verify 중복 로직을 이동시키면서 인터페이스를 사용한다면인터페이스를 구현한 추상클래스 public abstract class AbstractCaptchaHashProcessor implements CaptchaHashProcessor { protected final Encryption encryption; private final CaptchaLogPort captchaLogPort; @Override public Long verify(String hashedCode, Long userId) { // 추상 클래스로 이동한 중복 로직 ... } }구현체 1public class RandomCaptchaHashProcessor extends AbstractCaptchaHashProcessor { private static final SecureRandom RANDOM = new SecureRandom(); private final EncryptionProperties properties; public RandomCaptchaHashProcessor(Encryption encryption, CaptchaLogPort captchaLogPort, EncryptionProperties properties) { super(encryption, captchaLogPort); this.properties = properties; } @Override public HashResult hash(Long captchaId) { // 구현체마다 다름 ... } }구현체 2public class FixedCaptchaHashProcessor extends AbstractCaptchaHashProcessor { private static final String FIXED_IV = Base64.getEncoder().encodeToString(new byte[16]); public FixedCaptchaHashProcessor(Encryption encryption, CaptchaLogPort captchaLogPort) { super(encryption, captchaLogPort); } @Override public HashResult hash(Long captchaId) { // 구현체마다 다름 ... } }이렇게 구현할 수 있을텐데, 인터페이스를 사용하지 않는다면 hash 메서드까지 추상 클래스의 추상 메서드로 명시해서 상위 수준 클래스가 추상 클래스에 의존해도 될 것 같아서 고민이 됩니다! 이 질문을 작성하면서 다른 생각도 떠올랐는데요, CaptchaHashProcessor는 캡챠 코드를 암호화(hash)하고 캡챠 코드를 검증(verify)한다는 두 가지 책임을 가진 것 같아서 어쩌면 암호화 책임은 인터페이스와 그 구현체들로 제공하고, 검증 책임은 또다른 클래스에서 구현하는 것이 적절한가? 하는 생각도 듭니다... 좋은 강의를 제공해주시고 긴 질문 읽어주셔서 감사합니다.질문은 타인이 저에게 소중한 시간을 소비하는 것이라 생각해 강사님의 시간 낭비가 되지 않도록 영양가 있는 질문을 잘 하고싶습니다. 혹시나 질문의 내용 구성이나 태도, 질문을 이끌어낸 사고과정 등에서 부족한 부분이 보였다면 어떻게 개선하면 좋을지 말씀해주시면 감사하겠습니다!
-
미해결Flutter 테스트 기초
Mockito 강의 Exception
Mockito강의를 듣고 있는데요첨부된 자료 다운로드 후 실행을 했는데api 요청에서 Exception이 발생하고 있습니다.어떻게 해결해야하나요?
-
미해결쉬운 모바일 테스트 자동화 시작하기 : Appium Studio
Appium & Android Studio 설치 관련
안녕하세요 선생님 이번에 강의를 처음 듣게 되었는데요 자료에 남겨주신 Appium 설치 파일이 다운로드가 되지 않아 혹시 해당 강의를 따라할 수 있는 Appium이나 Android Studio를 다운로드 가능한 파일이나 참고할 설치 가이드가 있는지 궁금합니다~
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
controller 의 port 패키지의 service 인터페이스 사용
controller 패키지가 service 패키지에 의존해야하는데 interface를 controller의 port에 둠으로써 service가 controller에 의존하게 된다고 말씀하시고 수정한다고 했는데 수정이 없네요. service 인터페이스들을 service.port 패키지로 옮겨주면 될거 같습니다.
-
해결됨Practical Testing: 실용적인 테스트 가이드
고전파의 테스트 대역 사용 대상, 공유 의존성
안녕하세요복습을 진행하면서 단위 테스트(블라디미르 코리코프)를 같이 공부하는데, gpt와 씨름해 보아도 모르겠어서 질문 드립니다 ㅠㅠ책에 따르면 고전파의 테스트 대역 사용 대상은 공유 의존성으로 유일하고, 이것의 예로 데이터베이스를 들고 있는데요.우빈님의 강의에 따르면 이것은 고전파의 방식과는 거리가 멀어 보여서 혼란이 옵니다테스트 대역을 쓰고 싶다면, 공유 의존성(데이터베이스)은 가능하다라는 뜻 인걸까요?만약 그렇다면, 고전파가 테스트 대역 사용에 엄격한 방식이라고 이해했었는데, 데이터베이스를 유일한 모킹 가능성 영역이라고 보는 것이 납득하기 어렵습니다강의에서 가르쳐주신 것처럼 외부 서비스(메일)을 모킹 처리 하는 것이 더 나은 방식, 혹은 고전파 다운 방식이라고 생각되어서 혼란스럽습니다..
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
빌드 문제
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 1) 여기만 3.3.0(또는 3.2.5 등)으로 변경 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>demo</description> <properties> <java.version>21</java.version> <lombok.version>1.18.36</lombok.version> </properties> <dependencies> <!-- Spring Boot Starters --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-mail</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <!-- 기타 의존성 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>6.0.3</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <!-- Lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <!-- Jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.14.1</version> </dependency> <!-- Springdoc --> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> <version>2.0.2</version> </dependency> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-ui</artifactId> <version>1.6.14</version> </dependency> <!-- Test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- (선택) JDK 툴체인 강제 설정 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-toolchains-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <goals> <goal>toolchain</goal> </goals> </execution> </executions> <configuration> <toolchains> <jdk> <version>${java.version}</version> </jdk> </toolchains> </configuration> </plugin> <!-- 자바 21 + Lombok 어노테이션 프로세서 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <release>${java.version}</release> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </path> </annotationProcessorPaths> <fork>true</fork> </configuration> </plugin> <!-- Spring Boot Maven Plugin: Lombok 제외 유지 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
-
해결됨오브젝트 - 설계 원칙편
함수형 스타일에 대해선 어떻게 생각하시나요?
이제 꼭 함수형 언어를 사용하지 않더라도 요즘 언어들 대부분 함수형 언어의 아이디어나 장점들을 반영하는 트렌드인데, 회사에서도 코틀린을 사용 중이라 질문 드려봅니다.코틀린 라이브러리들을 사용하다 보면 함수형 스타일의 설계와 API들을 꽤 많이 보고 있기도 하고 특히 람다를 굉장히 많이 사용하는데 적절하게 람다나 함수형 스타일의 코드를 사용하는 기준이나 원칙들도 있으신지 궁금하네요.
-
해결됨오브젝트 - 설계 원칙편
값 객체 활용에 대해
안녕하세요. 항상 객체 지향의 본질을 가르쳐주시는 강의 정말 잘 듣고 있습니다. 실무에서 JPA를 사용할 때 값 객체 활용에 대해서도 궁금합니다. RDB 기준 하나의 테이블에 매핑되는 경우말고, 값 객체를 별도의 테이블로 매핑해야될 경우에도 많이 사용하시는지 궁금합니다.
-
미해결테스트 with Jest: 제로초에게 제대로 배우기
강의 교안
강의 안에 교안 얘기가 있는데 강의 교안이 어디있나요?
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
빌드 안 되시는 분들 참고
Maven resources compiler 어쩌구자바 버전 문제제 기준 pom.xml에서 java.version 21로 올리고 프로젝트 설정에서 SDK/모듈도 동일하게 설정했더니 해소 됐습니다NoSuchFieldError 어쩌구lombok 버전이 자바 버전과 안 맞음.pom.xml lombok dependency의 버전을 자바랑 맞추기 https://jinseobbae.github.io/java/2023/02/27/lombok-version-compatibility.htmlUnsupported class file major version 65스프링부트 버전 문제3.3.0으로 올리니까 해소됐습니다
-
해결됨오브젝트 - 설계 원칙편
실례지만 여기에 후기 올립니다.
영호님 강의 잘 들었습니다.객체지향적인 설계에 대한 근원이되는 내용에 관심이 많아영호님의 서적과 강좌를 자주 보게 되네요 본론시중에 나와 있는 서적과 강좌가 정말 잘 되어 있는 만큼사람들이 많이 사용하는 스프링 프레임워크에 적용한 예제도 가끔 있으면 어떨까 합니다.생각보다 이 부분이 제 주변인들의 가려운 부분이었어요예를 들면스프링을 사용하는 가정하에 비즈니스 계층에 적용해야하는데,다형성이 필요한 서비스의 경우 "인터페이스 - 구현체" 로 구축시구현체들을 Spring Bean으로 사용할 경우, 컴파일 시 구체적인 구현체가 아니라 에러가 나는데이럴때는 구현체를 매핑해주는 팩토리를 생성해서 사용해야된다와 같은 다소 객체지향과는 동떨어지지만 소소한 설명이 언급되어도 좋을 것 같습니다.아마 강좌나 서적을 보는 많은 사람들이 비슷한 생각일 것 같습니다."이 부분을 만약에 업무에 적용시킨다면 어떻게 해야 할까나?" 대부분 이런 생각이지 않을까 해서 드린 말씀입니다.항상 고품질의 강좌와 서적을 위해 애써주시는 영호님께 다시 한 번 감사드립니다.