Search
Duplicate

2021년 9월 2주차 회고록 - 퇴사, DTO의 사용범위

Facts

스프링 5주차 미션 진행 정리 및 피드백 학습
DTO의 사용 범위
Lombok과 같은 결과가 보장된 부분에 대한 테스트 예외 설정방법
@JsonProperty 애노테이션 학습
@ArgumentsResource 애노테이션 학습
Validation 학습
회사 퇴사 결정
카카오 코테 경험

Feelings

스프링 5주차 미션 진행 정리 및 피드백 학습

어느덧 코드숨도 5주차를 진행하게 되었다. 처음엔 미션자체만 보고 그렇게 어렵지 않으니 쉽게쉽게 과정 마칠 수 있으려나? 하던 때도 있고, 반대로 이런 디테일이나 멘트 그리고 테스트 코드를 작성하는게 너무 힘들어서 내가 이거 잘 마무리 지을 수 있으려나...고민도 했었지만, 지금은 그냥 미션을 수행하고 피드백을 받으며 발전해나가는 자체를 즐기고 있다. 수료를 하면 어떻고 못하면 어떤가. 듣기전보다 나아지는 내가 될 것은 확실한데..
이번주에는 유효성 검증 부분에 대한 기능에 대해 미션을 수행했는데, 안그래도 최근 김영한님의 강의에서도 Bean Validation을 배웠기에 아예 생소하진 않았지만 체득될정도로 실습을 한 것은 아니기에 기쁜 마음으로 학습하면서 진행을 했다. 실무도 그렇지만, 하다보면 내 생각대로 애노테이션에 딱 딱 맞게 진행이 안되었고, 생각할 부분에 대해 많이 고민을 할 수 있는 시간이였다.
입맛에 딱 맞는 애노테이션을 찾지 못해 직접 커스텀 애노테이션을 만들까도 생각했지만, 유효성 검증 로직을 직접 추가하는식으로 진행했었다. 그러면서 처음엔 직접 null check, empty check를 해줬지만, ValidatorFactory에서 검증기를 만들어서 검증 애노테이션을 활용하여 이미 있는 검증로직을 활용할 수 있어서 사용해보기도 했다.
그 다음으로 DTO의 사용범위에 대해서도 좀 더 학습을 진행했다. 이 부분은 예전부터 10명의 개발자와 얘기를하면 10명이 다 다르게 생각하거나 기준을 잡아서 이번에도 여러 개발자들과 의견을 나눠봤지만, 그 때 그때 다른것이고 나 역시 내가 생각한 기준으로 작성을 했는데, 내가 생각한 중점은 상황에 따라 달라지며 중점은 도메인 모델을 보호한다는 것 이였다. 조만간 따로 포스팅을 해서 생각과 지식을 정리해야 할 필요가 있을 것 같다.
그밖에 지금까지는 Lombok과 같은 라이브러리를 사용해 자동 생성되는 메서드들에 대한 테스트 케이스 작성과 같은 것을 exclude함으로써 무시하는 방법이나 비밀번호와 같이 외부로 노출하기 위험한 정보에 대해서 제약을 두는 @JsonProperty 속성에 대해서도 알아보고 했다.

회사 퇴사 결정

회사에 퇴사의견을 내고 왔다.
뭔가 급작스럽게 든 생각에 무작정 하기보다는 여러 문제들로 인해 내린 결정이다.
지금 회사는 작은 회사에 연봉도 높지는 않지만, 업무강도 자체는 낮은편이고, 금요일마다 재택에 사람관련해서 스트레스 받을일이 별로 없고, 출퇴근이 편하다는 장점이 있다. 그리고 사실 이 부분때문에 매번 퇴사를 고민하다가도 번복하고 있었다. 하지만, 미지근한 물에 삶아지는 개구리의 삶같다는 생각도 계속 했다. 회사가 너무 안좋으면 바로 뒤돌아보지 않고 퇴사를 하면 되고, 너무 좋으면 계속 다니면 될 문제지만, 여긴 이런저런 단점속에 이런저런 명확한 장점들로 인해 애매한 마음으로 계속 다니게 하니... 그래서 매번 트리거를 찾지 못해 2년 반동안 꾸역 꾸역 회사를 나갔다.
그러면서 정리했던 지금 회사의 장단점은 다음과 같았다.

장점

출퇴근 환경 : 집에서 문을 열고 나와 회사에 도착해 의자에 앉기까지 1시간
업무 강도 : 복불복이긴한데, 프로젝트를 시작하지 않은 상태에서는 개인공부를해도 노터치일 수준
이사님 두분이 다 현역 개발자 : 한 분은 GIS관련해서는 정말 전문가 수준이고 개발적으로는 이름만 안알려져있을뿐 내가 아는 개발자중 TOP 3안에 들 정도로 잘하시는 분. 언어의 장벽이 없고, 유연하게 처음 쓰는 라이브러리나 프레임워크로도 개발 뚝딱뚝딱 해내시고, 개발자 입장이다보니 일정산정에도 여유롭게 잡아서 야근이 잘 없게끔 하심.
모두 다 성격이 모나지 않아서 스트레스가 없음 : 직원들이 다 성격이 좋은편이고 존중해주는 분위기이기에 사람 문제로 스트레스받을일이 없음.

단점

경력 뻥튀기 : 내가 석사 + 나이가 좀 있어서 그런지 경력 뻥튀기가 0년차때부터 너무 심했음. 1년차때는 이미 5~7년차 중급개발자가되서 팔려나감. 이로인해 욕먹기 싫어서 매일 새벽까지 공부하고 지식 우겨넣으면서 욕안먹고 민폐안되려고 공부를 해야하니 장점이라고 해야할지...
낮은 연봉 : 같은 연차에 같이 스터디를 하던 지인들과 연봉을 비교하면 거의 1000 이상 낮은 편. 지금 회사에서 이사님에게 배울점이 많다고해서 불만을 가지진 않았지만, 명백히 단점.
회사에 중간계급이 없음. : 입사하고 바로 차장님이 퇴사하고 내 위로는 사실상 바로 이사님들뿐... 그렇기에 개발이아닌 실무적인 업무작업이나 응대 등 여러가지에 대해서 배울 사람이 없음. 이사님에게 직접 물어보는걸로는 제약이 명확하다. 그렇기에 연차는 쌓이고 개발 스킬이조금은 늘 지 모르겠지만, 3년차가 되었을때 실무나 문서작업부분에서 취준생과 비슷한 3년차 수준이면 문제일 것으로 보임.
코드리뷰나 스터디 문화가 없음 : 내가 프로젝트에서 진행한 코드에 대한 리뷰문화가 없고 스터디도 활성화되지 않음. 초창기에 내가 세미나발표식으로 JPA를 두달정도 발표를 했지만, 그외에는 없는 편.. SI라서 테스트작성도 거의 없는편이고 혼자 시도를 하지만, 일정에 테스트케이스 추가에 대한 일정은 없는편이라 함부로 시도하다간 일정에 쫒겨 야근하기 쉽상..
장단점을 비교할 때 아직까진 장점이 더 크다고 생각해 여기서 퇴근하고 공부하면서 실력쌓아서 이직해야지 라는 생각으로 버티고있었다가, 이번에 파견얘기가 나오면서 여기에 내가 고급 PL로 뻥튀기가 되고 내년 2월까지는 해야한다는 얘기에, 이미 이 파견을 하고 안하고의 문제가 아니라 허위경력 뻥튀기의 정도가 너무 심해서 정이 떨어졌기에 퇴사를 결심하게 되었다. 이직후 퇴사가 베스트였겠지만, 상황도 상황이고, 이리된거 배수의진을 치고 정말 열심히 준비해서 이직을 해야겠다..
근데 감사하게도 꽤 여러군데서 직장 소개및 프리 소개도 들어와서 여태 공부 꾸준히 한게 헛된건 아니였구나 하는 새각도 든다. 하지만, 민폐 끼치기가 싫기도하고 면접도 경험을 할 필요가 있어서 모두 보류한 상황...

카카오 코딩 테스트 경험

전혀 알고리즘이나 코테준비를 한 적도 없는 상태로 늦게 참가해서 2시간정도 코테를 봤다. 그냥 지금 코테 수준이 어느정도이고 얼마나 어렵나 볼 요량이였는데, 5문제중 실제로 읽은 문제는 3문제정도였고 2문제정도를 문제자체만 통과한 것 같다. 여러 테스트조건이나 코드의 깔끔함은 엉망인 것 같고.. 따로 공부를 얼마 안하고 기법이나 이런 코테에서 inner class를 만들어서 사용해도 되는지 등등 지식이 없어서 그냥 생각나는대로 풀어본 것 같다.
9월 말부터는 프로그래머스에서 알고리즘 스터디도 시작하니 이것도 열심히 참가해봐야겠다.

Finding

스프링 5주차 미션 진행 정리 및 피드백 학습

DTO의 사용 범위

데이터 전송객체인 DTO(Data Transfer Object)는 프로세스 간에 데이터를 전달하는 객체라 지칭한다.
사용자에게 도메인을 노출하지 않고 DTO를 통해 데이터를 주고받아서 처리를 하는데 여기서 두 가지 이슈를 생각할 수 있다.
DTO는 어디까지 사용할 수 있는가? (Ex: Controller, Service, Repository, Domain, ...)
DTO Entity 변환은 어디서 이루어져야 하는가?
결론부터 얘기하자면 정답은 없는 것 같다는게 내 생각이다. 핵심은 이것을 어디까지 사용하고 어디에서 변환할지가 중요한게 아니라 도메인 모델 보호인 것 같다.
위 북마크 글에서는 DTO의 변환 로직을 어디에 위치시켜야 하느냐에 대해 얘기하는데 결국 리포지토리에는 위치시키면 안되고 Application Service에 있어야 한다고 얘기를 한다. 즉, 이 변환 로직이 어디에 있느냐에 따라 서비스가 도메인 과 DTO중 무엇을 반환할 것인지에 대해 알 수 있다.
다음은 DTO를 어디서 변환하느냐에 따라 발생할 수 있는 문제점이다.
마틴 파울러는 서비스 레이어에서 DTO로 변환하는것을 제시한다.
A Service Layer defines an application's boundary [Cockburn PloP] and its set of available operations from the perspective of interfacing client layers. It encapsulates the application's business logic, controlling transactions and coor-dinating responses in the implementation of its operations.
또한, 반환 타입 역시 도메인을 컨트롤러로 반환해도 결국 컨트롤러에서 View 영역으로 반환하기위해서는 민감한 정보를 제외한 DTO를 만들어 반환해야하는데, 이 작업이 복잡할 경우 컨트롤러에 위치하는게 맞지 않다고 생각하고, 더하여 하나의 DTO에 포함될 정보가 하나의 도메인으로 해결이 되지 않는 경우 다른 서비스나 도메인을 사용하게 되면 서비스 로직이 컨트롤러에 포함되게 된다.
그렇기에 나 같은 경우에는 서비스에서 DTO를 사용하여 DTO를 반환하는 방식을 선호한다.
하지만, 이런 의견도 있다.
서비스 레이어에는 DTO가 아닌 도메인을 받아야 여러 컨트롤러에서 해당 서비스를 사용할 수 있다. 하지만, 실무에서는 보통 여러 종류의 컨트롤러에서 한 서비스를 사용하기보단 한 종류의 컨트롤러에서 서비스를 사용하기에 엄격하게 DTO의 진입을 막을 필요는 없다. 그렇기에 DTO 진입을 허용하되 서비스 메소드 상위에서 DTO 체크 및 도메인 변환을 하여 실제 서비스에서는 DTO를 사용하지 않도록 한다. 반환 타입 역시 도메인을 반환하여 컨트롤러에서 DTO를 만들어 반환한다.
사실 내심 생각하는 부분은 회사에서 팀장급이 정해준대로 가게 되있다... 라는 생각도 들지만, 개인적으로는 컨트롤러에서는 전달받은 DTO를 그대로 서비스에 전달하고 DTO를 반환받아 그대로 화면단에 반환해주는 역할정도로 충분하지 않을까? 생각을 한다.

Lombok과 같은 결과가 보장된 부분에 대한 테스트 예외 설정방법

Lombok을 사용하면서 상당히 많은 부분에서 편리해졌지만, JaCoCo의 코드 커버리지를 체크하면서 신경쓸 일이 많아졌다. 특히 이번 미션에서 @Builder 애노테이션의 경우 이 빌더로 생성된 Builder 객체의 toString이 테스트되지 않았다고 커버리지를 깍아먹고 있는데, 그렇다고 이런 결과가 어느정도 보장된 Lombok 메서드의 toString까지 다 테스트케이스를 작성하기에는 비용 낭비라는 생각이 들었다. 그래서 이런 부분에 대해 exclude 하는 법을 조사했는데, 나는 @Generated라는 애노테이션과 exclude 설정을 통해 해결했다.
1.
Lombok.config 파일 생성
2.
lombok.addLombokGeneratedAnnotation = true 추가

@JsonProperty 애노테이션 학습

미션을 진행하며 유효성 검증 로직을 넣다보니 무심결에 비밀번호를 그냥 노출해서 반환하고 있었다는걸 알게되었다. 개인 프로젝트나 따로 할 때는 아예 별도의 DTO를 만들어서 사용하고는 했는데, 이번 기회에 다른 좀 더 나은 방법이 없나 고민을 하며 구글링을 하게되었고 그러다가 @JsonProperty를 이용하는 방법을 알게 되었다. 보통 해당 애노테이션은 serverclient 사이에서 property 명이 다를 경우 일치시키기 위해서만 사용을 했었는데, 그외에 access라는 속성이 있었다. 해당 속성을 사용하여 property를 읽기, 쓰기, 읽기/쓰기 등 내가 접근에 대해 제어를 할 수 가 있는데, 이를 통해 client에서 api로 전달 받을 때는 password도 받을 수 있지만 외부로 노출할 때는 password는 노출하지 않도록 설정할 수 있었다.
@NotBlank @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private String password;
Java
복사
그 밖에도 여러 속성이 있는데 클래스를 트레이싱해 보면 자세한 javadocs가 작성되어있다.
access : getter/setter 의 접근 가시성을 선택하는 선택적인 속성으로 설정에 따라 가시성을 제어할 수 있다. (Access라는 내부의 enum 객체의 AUTO, READ_ONLY, WRITE_ONLY, READ_WRITE)
defaultValue : 해당 필드에 기본 값을 지정할 수 있다. 따로 지정하지 않으면 공백""이 저장된다.
index
:해당 프로퍼티의 숫자 인덱스를 나타내는 속성으로 바이너리 형식으로 사용된다.
required
: 해당 property의 필수 값 여부를 지정하는 속성으로 기본 값은 false인데 true로 지정할 경우 해당 property에 값이 없을 경우 역직렬화에 실패한다.
value
: 해당 property의 이름을 지정할 수 있다.

@ArgumentsResource 애노테이션 학습

이번에 계층형 테스트 케이스를 작성하다보니 MethodResource를 사용한 인자 값 주입을 쓸 수 없었다. 그래서 메서드를 통한 테스트 인자 값 주입을 어떻게 해야하나 고민을 하면서 찾아 본 결과 @ArgumentsResource라는게 있다는걸 알았고, 이를 사용해서 테스트 케이스를 작성해봤다.
필드에 공백 혹은 null값이 있는 잘못된 회원 정보를 인자로 받고 싶었는데, 이렇게 Arguments를 받기 위해서는 ArgumentProvider를 구현하는 구현체를 만들 필요가 있었다.
/** * 필드에 공백(or null)이 포함된 회원 객체 매개변수를 전달한다. */ public class ProvideInvalidAccountArguments implements ArgumentsProvider { @Override public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception { String[][] params = {{"name", ""}, {"name", null}, {"email", ""}, {"email", null}, {"password", ""}, {"password", null}}; final List<AccountSaveData> invalidProducts = IntStream.range(0, 6) .mapToObj(index -> { final AccountSaveData accountSaveData = AccountSaveData.of(ACCOUNT_NAME, ACCOUNT_EMAIL, ACCOUNT_PASSWORD); ReflectionTestUtils.setField(accountSaveData, params[index][0], params[index][1]); return accountSaveData; }).collect(Collectors.toList()); return Stream.of(Arguments.of(invalidProducts)); } }
Java
복사
여기서 한 걸음 더 나아가 상태전이 배열을 나타내는 enum객체를 만들어 볼까 했지만, 구현 비용이 더 드는 것 같아 간단한 String 배열을 통해 구현했다. 더하여 다른 테스트 케이스에서도 ArgumentResource 애노테이션을 이용해 해당 ArgumentProvider를 사용할 수 있어서 유용했다.

Bean Validation 학습

5주차 미션과 김영한님의 MVC2 강의 내용중 Validation과 Bean Validation 그리고 오류 메세지 챕터가 얽혀서 내게 유효성 검증에 대한 많은 피드백을 줬다.
미션에서는 @Valid애노테이션을 사용하여 유효성 검증을 했는데, hibernate 에서는 @Validated라는 애노테이션도 있고 이를 사용할 수 있음을 인지하면 좋다.
hibernate의 Bean Validation은 그래들의 경우 다음과 같은 의존관계를 추가해야 한다. implementation 'org.springframework.boot:spring-boot-starter-validation'
그리고 더 우선적으로 이 Bean Validation은 특정 구현체라기보다는 Bean Validation 2.0(JSR-380)이라는 기술 표준으로 여러 검증 애노테이션과 인터페이스의 모음이다.
javax.validation으로 시작하는 검증기는 특정 구현에 관계없이 제공되는 표준 인터페이스이고, org.hibernate.validator로 시작하는 검증기는 validator 구현체를 사용할 때만 제공되는 검증 기능이다.
hibernate validator annotation documents

Affirmation

스프링 5주차 과제풀이 시청 및 6주차 미션 시작
채용 공고 크롤링 시작
자료구조 및 알고리즘 준비
5주차에 얻은 키워드를 포스팅으로 정리하며 체화