또 한번의 시작
퇴사를 하고 개발 인생에서 하나의 터닝포인트가 되었던 코드숨 멘토링을 끝나고 고민을 했었다.
지금 부족한 점이 뭘까? 뭘 더 채워야 할까?
물론 공부를 하면 할 수록 부족한 점이 계속 보이긴 했지만, 당장 급한 것이 뭘까 싶었다.
퇴사 후 지금까지 했던 공부들을 되돌아보면서 문득 생각이 들었다.
- "내가 진짜 테스트 코드를 효율적으로 짜는 역량이 생긴건가?"
- "내가 복잡한 비즈니스 로직에서도 코드를 클린하게 유지할 수 있을까?"
내 인생 멘토님인 향로님에게 고민을 털어놓았더니 아래와 같은 조언을 해주셨다.
- "복잡한 비즈니스 로직에서도 클린하게 코드를 유지할 수 있는 연습을 해보는 것이 좋아요"
- "코드숨에서 진행한 미션들은 아쉽게도 비즈니스 로직이 그렇게 복잡한 부분은 보이지 않네요"
- "또한 코드숨에서는 Mock을 사용한 테스트 코드만 사용하신거 같은데, Mock 없는 테스트를 짜보시는것도 좋을 수 있어요"
- "CI/CD를 진행하는것도 좋지만 인프라쪽보다 우선시 되어야 할 것은 애플리케이션(코드)이라고 생각해요"
그래서 생각한 것이 NEXTSTEP의 ATDD, 클린 코드 with Spring 과정이었다.
해당 과정을 선택하게 된 목적은 다음과 같다.
- 복잡한 비즈니스 로직에서도 코드를 깔끔하게 유지하는 역량
- Mock 없는 테스트, 인수 테스트 등 다양한 테스트 전략
- 프러덕션 코드를 마음 편히 지지고 볶을 수 있도록 신뢰할 수 있는 테스트를 작성하는 역량
사실 Mock 테스트는 코드숨 회고에서도 여러번 얘기했지만, 개인적으로는 그닥 신뢰가 안가는 테스트라고 생각이 들었다.
또 한번 열심히 달려나가서 효율적이고 다양한 테스트 전략과 복잡한 비즈니스 로직에서도 코드를 클린하게 유지하는 역량을 길러보려고 한다.
인수 테스트
첫 라이브 강의에서는 ATDD의 개념과 프로세스, 인수 테스트 작성 방법 등을 설명해주셨다.
아래는 개념들을 학습하면서 머릿속에 정리하는 용으로 적어내려간 내용들이다.
ATDD
- 다양한 관점을 가진 팀원(기획, 개발, QA)들과 협업을 하기 위한 애자일 방법 중 한가지
- 기획 단계부터 인수 테스트를 통해 공통의 이해를 도모하여 프로젝트를 진행하는 방법
- 모든 구성원이 결과물에 대한 싱크를 맞추고 작업에 착수하는 효과
ATDD 개발 프로세스
인수 조건 정의 → 인수 테스트 작성 → 문서화(RestDocs) → 기능 구현 → 테스트 리팩토링
인수 테스트
BDD와 ATDD의 다른점
- BDD는 행동 기반 테스트로 기능의 동작에 더 중점을 둠
- ATDD는 정확한 요구 사항을 포착하는데 중점을 둠
객체지향 생활체조
강의에서는 따로 말해주시진 않았지만 강의 자료에 따로 있던 내용 중에 객체지향 생활체조라는 내용이 있었다.
자료에서는 간략하게만 적혀있었는데, 어디선가 한번쯤 들어봤던 키워드였던 것 같아서 이 기회에 머리에 확실히 박으며 공부해보았다.
아래 내용도 머릿속에 정리하는 용도로 나 자신과 얘기하는 대화체로 작성했다.
1. 한 메서드에 오직 한 단계의 들여쓰기(indent)만 한다.
- 중첩 if 같은 것을 하지 않는다 → 가독성 감소
- 메서드는 한가지의 일을 매우 잘하게끔 설계해야 하는데, 중첩문이 여러개일 경우 한가지 일만 하지 않을 확률이 높다고 생각함
2. else 예약어를 쓰지 않는다
- else를 사용하면 위에 있는 모든 if 조건문을 일일히 타고 내려가면서 눈으로 확인해야됨
- early return 방식을 사용하면 좋을 듯 함
3. 모든 원시값과 문자열을 포장한다.
- 단순히 리터럴 값만으로는 아무런 의미를 표현할 수 없다 (오직 변수명으로만 표현 가능)
- 객체로 포장한다면 상태를 객체 스스로 관리(유효성 검사 등)할 수 있고, 왜 사용하는지 보다 명확하게 전달 가능
4. 한 줄에 점을 하나만 찍는다.
.get.get 금지
-
디미터 법칙 : 멀리 떨어져 있는 낯선 객체에 메시지를 보내는 설계를 피하라
- 자기 자신이랑 친구까지한테만 메시지를 보내야함 (메서드 호출)
-
객체 자신의 메서드들
-
메서드의 파라미터로 넘어온 객체들의 메서드들
-
메서드 내부에서 생성, 초기화된 객체의 메서드들
-
인스턴스 변수로 가지고 있는 객체가 소유한 메서드들
public class Member {
private Gender gender;
public void addMember(Member member) {
}
public void updateMember(Age age) {
age.get();
}
public void Demeter_법칙을_잘지키기() {
addMember(new Member());
Name name = new Name("ALEX");
name.getFullName();
gender.get();
}
}
- 즉 한 다리 건넌 객체의 메서드를 호출하는 것은 디미터 법칙에 위배된다
-
묻지 말고 시켜라 (Tell, Don’t Ask) : 객체의 상태는 객체 내부의 행위를 통해서만 변경해야 한다
- 직접 가져와서 조건식으로 판단하지말고 객체에게 직접 판단하라고 명령을 지시해야한다
- 캡슐화를 통해 객체는 자료를 숨기고 함수를 공개
5. 줄여쓰지 않는다(축약 금지)
의도가 분명하게 이름을 짓자
- 변수명을 축약하면 한번에 알아보기가 힘들다 → 가독성 감소
- 문맥상 중복되는 단어는 자제하자 → 가독성 감소
- 클래스명에 이미 있는 내용을 변수에 또 쓰지 말자
(ex. Person 클래스의 getPersonName() → Person 클래스의 getName())
- 메서드명이 너무 길어서 축약할 경우, 메서드의 역할이 여러 개인지 먼저 확인하자
6. 모든 엔티티를 작게 유지한다.
- 50줄 이상 되는 클래스와 파일이 10개 이상인 패키지는 지양하라
- 즉 50줄 이상 되는 클래스는 한 가지 이상의 일을 할 확률이 높다
- 만약 클래스를 작게 작성하기가 애매할 경우(ex. 같이 있어야 되는 동작의 묶음이 있을 때)는 패키지를 최대한 활용한다
- 따라서 패키지 또한 클래스처럼 응집력 있고 단일한 목표가 있어야 한다
이 부분은 논란이 많은 내용이지만, 따로 찾아본 결과 OOP를 처음 연습할 때는 기준을 명확하고 구체적으로 잡야한다고 박재성님이 얘기하셨다.
따라서 그냥 수치적으로 기준을 50줄과 10개로 잡았지만 이를 맹신하기보다는 하나의 기준을 잡고 의식적인 연습을 해보라는 의도인것 같았다.
- 우아한테크세미나 - TDD 리팩토링 by 자바지기 박재성님
7. 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.
대부분의 클래스가 인스턴스 변수 하나만으로 일을 하는 것이 마땅하다. 몇몇 경우에만 두개의 변수가 필요할 때가 있다- 마틴 파울러
- 인스턴스 변수가 많아질수록 클래스의 응집도는 감소
- 해당 법칙을 실현하려면 기존 하나의 객체에 매우 세부 객체들로 쪼개야 할 것 같음
8. 일급 컬렉션을 쓴다
- 일급 컬렉션 : Collection을 Wrapping하면서, Wrapping한 Collection 외 다른 멤버 변수는 없는 객체
- 즉 오직 하나의 컬렉션을 상태로 가지고, 그 상태만을 위한 행위들을 제공하는 커스텀 자료구조
- 컬렉션의 불변을 보장하기 위해, 컬렉션의 값을 변경할 수 있는 메서드가 없는 컬렉션을 만들자
- final 키워드는 불변을 만들어주는 것이 아닌, 재할당만 금지한다
- 이로써 하나의 컬렉션 값이
일급 컬렉션 객체
를 통해 상태와 행위를 한 곳으로 관리하는 효과를 가지게 된다
9. 게터/세터/프로퍼티를 쓰지 않는다
- 묻지 말고, 시켜라 (Tell, Don’t Ask) 원칙
- 객체에게 책임이 있는 작업은 객체에게 직접 시켜야 한다
- 객체의 자율성을 보장하며, 객체는 능동적으로 행동할 수 있도록 설계해야 한다
- 하지만 getter에 경우에는 예외적으로 Presentation 계층에서는 외부에 메시지를 전달해야 하므로 getter가 필요하다
- 따라서 getter는 정말 필요할 때는 사용하되, 무분별한 남발은 불필요한 객체 내부 구현의 노출로 이어진다 → 응집도 하락 & 캡슐화 위반