[Readable Code: 읽기 좋은 코드를 작성하는 사고법 회고 1주차

출처 : Readable Code: 읽기 좋은 코드를 작성하는 사고법 / 박우빈

 

1. 회고

저자께서 회고 방식에 대한 아티클을 소개해주셨고 KPT로 진행 후 주차별로 다른 회고 방식을 적용해보려고 합니다.

 

Keep(만족했고 지속할 부분)

  • 단순히 따라치는 수준에 그치더라도 직접 코드 작성

     

  • 미션 전 수강 내용 훑어보고 진행하기

 

Problem(부정적 또는 아쉬웠던 부분)

  • 강의 수강 전에 목표 달성 실패

    • 목표 : 코드 분석 및 수강 전 리팩토링한 코드와 수강 후 리팩토링된 코드 비교

    • 실제 : 코드 분석은 했으나 리팩토링까지는 진행하지 못함

     

Trying(Problem 해결 방식으로 다음에 시도해볼 점)

  • 목표 설정 후 시간제한 두기

    • 시간제한 없이 루즈하게 진행하여 목표 달성도 실패했고, 결과물도 만족스럽지 못함

 

2. 학습 내용 요약

추상(섹션1~2)

이름짓기

  • 단복수에 의미 부여

  • 줄임말 사용하지 않기

  • 도메인 언어 사용(유행어, 은어, 방언 금지)

  • 좋은 코드 보고 습득

  • 필드 이름은 추상화하지 않음

  • 메서드명은 내부 처리 내용을 추상화

     

 

메서드 선언부

메서드 선언부 : 반환타입 + 메서드명 + 파라미터

메서드 시그니처 : 메서드명 + 파라미터

반환타입에 대한 고민 : 반환할만한 값이 있는지? boolean이라면 true/false가 무엇을 의미할지?

파라미터가 날짜 형태라면 String 형태보다는 LocalDate가 적절해보임

전치사 잘 활용하기

메서드 내에서 동일한 추상화 레벨로 묶여야함

매직넘버 / 매직스트링 : 상수로 추출되지 않은 숫자나 문자 -> 리팩토링할 때 실제 의미가 같은 데이터만 변경했는지 확인 필요

 

논리, 사고의 흐름

Early Return

if(){}

else if(){}

else{}

구조 보다는 개별 if문과 return 사용(if의 조건을 else 까지 기억하기 어려움)

 

사고의 depth 줄이기

  • 중첩 분기문 / 중첩 반복문

코드 분석이 어렵다면 depth 1로 줄이는 것 고려, 그러나 모든 것을 메서드로 추출하면 오히려 가독성이 떨어질 수 있음

  • 사용할 변수는 가깝게 선언하기

공백 라인을 대하는 자세

비슷한 역할단위로 끊어주기

 

부정어를 대하는 자세

!isLeft

=> isRight, isNotLeft ( 부정 연산자 !의 가독성이 떨어짐)

 

해피 케이스와 예외 처리

예외 발생 가능성 낮추기 - 외부와의 접점

의도한 예외와 예상치 못한 예외 구분

return null 자제,

Optional 사용 고려(단, Optional은 비싼 객체이므로 꼭 필요한 경우에만 사용)

Optional을 파라미터로 받는 것은 안티패턴(Optional이 가진 데이터 null, optional null)

Optional 해소 - isPresent().orElseGet(), orElseThrow(), ifPresent(), ifPresentOrElse() 사용

++ orElse(), orElseGet(), orElseThrow() 차이 숙지

 

객체 지향 패러다임(섹션4)

객체지향 설계

  • 객체와 외부 세계는 공개 메서드로 소통함

  • 책임 분리

  • 1개의 관심사로 명확하게 책임 정의

  • setter 사용 자제

  • 객체에서 데이터를 꺼내어(getter) 분기처리하는 것이 아니라 공개 메서드에 필요한 정보를 입력하고 true/false 확인

  • 필드 수는 적을 수록 좋음 (totalPrice 같은 것은 성능상 이유가 아니라면 필요할 때마다 계산하여 반환

     

 

SOLID

  • SRP

    • 하나의 클래스는 하나의 변경 이유(책임)만 가져야 한다

  • OCP

    • 확장에는 열려있고 수정에는 닫혀있다 -> 기존 코드 변경 없이 시스템 기능 확장

  • LSP

    • 부모 클래스가 자식 클래스를 완전히 대체할 수 있어야한다.

    • 자식 클래스끼리 호환되지 않는 기능은 부모 클래스에서 제외

  • ISP

    • 사용하지 않는 인터페이스에 의존하면 안됨(3개 중 2개는 쓰는데 1개는 사용하지 않는 경우 인터페이스를 분리해야함)

  • DIP

    • 의존성의 순방향 : 고수준 모듈이 저수준 모듈 참조

    • 의존성의 역방향 : 고수준(고추상), 저수준(저추상) 모듈 모두 추상화에 의존

      • 구현체에 의존하는 것이 아니라 구현체의 추상(인터페이스)에 의존

++ 참고

  • DIP(Dependency Inversion Principle)

  • DI(Dependency Injection) - "3" 제 3자가 의존성 주입

  • IoC(Inversion of Control)

 

객체지향 적용하기(섹션5)

상속과 조합

  • 상속보다는 조합

    • 상속은 결합도가 높음

    • 인터페이스 활용

    • 부모의 필드를 직접 참조하지 않는 것이 좋음

Value Object

  • 도메인의 특정 개념을 추상화하여 표현한 객체

  • 불변성(final), 동등성(equals(), hashCode() 등, 내부 값이 같으면 같은 객체 취급), 유효성 검증(객체 생성 시점) 등 보장 필요

++ VS Entity

  • Entity

    • 단일 필드 식별자

    • 식별자만 같으면 다른 필드 값이 달라도 동등한 객체 취급

  • VO

    • 전체 필드가 식별자

    • 모든 필드가 같아야 동등한 객체취급

일급 컬렉션

  • 일급시민(ex 함수)

    • 변수로 할당 가능

    • 파라미터로 전달 가능

    • 함수의 결과로 반환 가능

  • 일급 컬렉션

    • 컬렉션만을 유일하게 필드로 가지는 객체

    • 컬렉션을 객체와 동등한 레벨로 다루기 위함

    • 단 하나의 컬렉션 필드만 가짐

    • 가공 로직 및 테스트 작성 가능

    • 반환할 때는 getter로 객체 주소를 반환하는 것이 아니라 새로운 컬렉션을 반환해야함

 

Enum의 특성과 활용

  • 상수와 상수 관련 로직 집합

  • 도메인 개념과 기능 명시 가능

  • 변경이 잦은 개념은 DB로 관리

 

다형성 활용하기

  • OCP

    • 조건을 만족하는가?

    • 만족하면 행위 수행

 

숨겨져 있는 도메인 개념 도출하기

  • 도메인 지식은 발견하는 것

  • 객체지향은 현실을 흉내내는 것

    • 현실에서 인지하기 어려운 개념도 도출해서 사용할 때가 있음

  • 설계할 때는 최대한 미래를 예측해서 진행하고 틀렸을 때 언제든 돌아올 수 있도록 코드를 만들어야함

     

 

 

댓글을 작성해보세요.

채널톡 아이콘