워밍업 클럽 2기 BE 클린코드&테스트 발자국 1주차
Day 2. 추상과 구체
추상과 구체
추상 (抽象)
사물을 정확하게 이해하기 위해서 사물이 지니고 있는 여러 가지 측면 가운데서 특정한 측면만을 가려내어 포착하는 것이다. 어떤 일면만을 추상하는 것은 다른 측면을 버린다는 것과 같다. (위키백과)
추상은 항상 구체적인 실재에서 시작해야 한다. - Pablo Picasso
추상화의 가장 대표적인 행위
이름을 짓는다.
이름 짓기
단수와 복수 구분하기
이름을 줄이지 않기
은어/방언 사용하지 않기
좋은 코드를 보고 습득하기
메서드와 추상화
잘 쓰여진 코드라면, 한 메서드의 주제는 반드시 하나다.
메서드 선언부
반환타입 메서드명 (파라미터) {}
메서드 선언부: 반환타입 메서드명 (파라미터)
메서드 구현부: {}
메서드 시그니처: 메서드명 (파라미터)
추상화 레벨
하나의 세계 안에서는, 추상화 레벨이 동등해야 한다.
매직 넘버, 매직 스트링
의미를 갖고 있으나, 상수로 추출되지 않은 숫자, 문자열 등
미션 - 생각나는 추상과 구체의 예시
Winter is coming
지구가 태양을 공전하여 태양의 고도가 점차 낮아진다.
이로인해 햇빛의 강도가 약해져 기온이 감소한다.
북쪽의 차가운 공기가 내려오고 습한 공기와 만나게 되면 눈이 내린다.
Day 3. 논리, 사고의 흐름 | 객체 지향 패러다임
뇌 메모리 적게 쓰기
“정리 시스템에서 중요한 과제는 최소의 인지적 노력으로 최대의 정보를 제공하는 것이다.”
- 대니얼 J. 레비틴, 「정리하는 뇌」, 와이즈베리, 2015, 134p
뇌는 한 번에 한 가지 일 밖에 하지 못한다. 멀티태스킹? 그건 저글링일 뿐.
- 요한 하리, 「도둑맞은 집중력」, 어크로스, 2023, 60p
Early return
Early return으로 else의 사용을 지양
사고의 depth 줄이기
중첩 분기문, 중첩 반복문
‘무조건 1 depth로 만들어라’가 아니다!
사용할 변수는 가깝게 선언하기
공백 라인을 대하는 자세
공백 라인도 의미를 가진다.
부정어를 대하는 자세
부정 연산자(!)의 가독성은 낮다.
해피 케이스와 예외 처리
사람은, 해피 케이스에 몰두하는 경향이 있다.
Null을 대하는 자세
항상 NullPointException을 방지하는 방향으로 경각심 가지기
Optional에 대해 orElse(), orElseGet(), orElseThrow()의 차이 숙지
추상의 관점으로 바라보는 객체 지향
객체 = 데이터 + 코드
협력과 책임
캡추상다
관심사의 분리
객체 설계하기
새로운 객체를 만들 때 주의할 점
1개의 관심사로 명확하게 책임이 정의되었는지 확인하기
생성자, 정적 팩토리 메서드에서 유효성 검증이 가능하다.
setter 사용 자제
getter도 처음에는 사용 자제. 반드시 필요한 경우에 추가하기
필드의 수는 적을수록 좋다.
도메인 지식은 만드는 것이 아니라 발견하는 것
미션 - 읽기 좋은 코드로 리팩토링
public boolean validateOrder(Order order) {
if (order.hasNotItem()) {
log.info("주문 항목이 없습니다.");
return false;
}
if (order.hasNotTotalPrice()) {
log.info("올바르지 않은 총 가격입니다.");
return false;
}
if (order.hasNotCustomerInfo()) {
log.info("사용자 정보가 없습니다.");
return false;
}
return true;
}
class Order {
private List<String> items = new ArrayList<>();
private Long totalPrice;
private String customerInfo;
public boolean hasCustomerInfo() {
return customerInfo != null && !customerInfo.isEmpty();
}
public boolean hasNotCustomerInfo() {
return !hasCustomerInfo();
}
public boolean hasNotItem() {
return !items.isEmpty();
}
public boolean hasTotalPrice() {
return totalPrice != null && totalPrice > 0;
}
public boolean hasNotTotalPrice() {
return !hasTotalPrice();
}
}
Day 4. SOLID
미션 - 자기만의 언어로 정리한 SOLID
SRP: Single Responsibility Principle
클래스는 하나의 책임, 즉 변경 이유를 한 가지만 가져야 한다. 한 가지 일을 잘 처리하도록 해야 유지보수가 쉬워진다.
OCP: Open-Closed Principle
새로운 기능이 추가할 때 기존 코드를 변경하지 않고 확장이 가능해야 한다.
LSP: Liskov Substitution Principle
부모 클래스의 기능을 자식 클래스에서도 사용할 수 있어야 한다.
ISP: Interface Segregation Principle
하나의 책임이 있는 인터페이스 여러 개로 나눈다. 그래야 필요한 인터페이스에 대해서만 구현할 수 있다.
DIP: Dependency Inversion Principle
하나의 모듈이 다른 모듈은 참조하지 말고 추상화에 의존해야 하고, 구체적인 사항은 나중에 정의해야 한다.
Day 5. 객체 지향 적용하기
상속과 조합
조합과 인터페이스를 활용하는 것이 유연한 구조
상속을 통한 코드의 중복 제거가 주는 이점보다, 중복이 생기더라도 유연한 구조 설계가 주는 이점이 더 크다.
Value Object
도메인의 어떤 개념을 추상화하여 표현한 값 객체
불변성
동등성
유효성 검증
일급 컬렉션
일급 시민의 조건을 만족하는 컬렉션
컬렉션을 포장하고 유일한 필드로 가지는 객체
Enum의 특성과 활용
Enum은 상수의 집합이며, 상수와 관련된 로직을 담을 수 있는 공간이다.
만약 변경이 정말 잦은 개념은, Enum보다 DB로 관리하는 것이 나을 수 있다.
다형성 활용하기
변하는 것과 변하지 않는 것을 분리하여 추상화하고, OCP를 지키는 구조
숨겨져 있는 도메인 개념 도출하기
완벽한 설계는 없다. 그 당시의 최선이 있을 뿐.
출처
댓글을 작성해보세요.