CS공부(개념)/독후감

클린코드 1주차: 깨끗한 코드, 의미있는이름, 그리고 함수

cantor 2023. 8. 6. 16:23

로버트 C 마틴

클린코드 북 스터디를 하며 작성한 독후감 겸 요약글입니다.

1장 깨끗한 코드

나쁜 코드의 안 좋은 점을 통해 클린코드의 필요성을 역설하고 그 특징을 묘사합니다.

책 제목이 클린 코드인 만큼 주의 깊게 읽었습니다.

나쁜 코드로 치러야 하는 대가

더러운 코드의 누적은 점진적으로 업무 효율을 하락시키고,

종국에는 잘 성장하던 서비스가 문을 닫는 이유가 될 수 있습니다.

 

코드를 깔끔하게 작성하는 것은 개발자의 만족감을 위한 요소가 아닌

프로젝트의 생존 을 위한 행위라는 인상을 받았습니다.

깨끗한 코드란?

  • 함수와 클래스들이 한 가지 일을 잘하는 코드
  • 읽고 이해하기 쉬운 코드
  • 기능 추가 및 수정이 쉬운 코드
  • 시간을 들여 정리한 코드
  • 중복이 없고, 추상화가 잘되어있는 코드
  • 각 부분이 짐작했던 기능을 제대로 수행하는 코드

보이스카우트 규칙

캠프장을 처음 방문했을 때보다 더 깨끗이 정리하고 떠나라.

 

깨끗한 코드를 정의하는 추상적인 항목을 보면서

디자인 패턴과 설계를 얼마나 깊게 공부하고,
프로젝트를 시작할 때 얼마나 숙고를 해야 할까 하는 생각이 들었습니다.

 

하지만 보이스카우트 규칙을 등불로 삼는다면,
큰 문제가 되지 않을 거 같습니다.

 

처음부터 완벽하게 시작하거나, 프로젝트의 모든코드를 한번에 뜯어고칠 순 없습니다.

매번 코딩을 할 때 이전에 만든 함수하나, 객체하나 리팩터링 하는것으로 충분합니다.

여담

tech meet에서 전해 들은 이야기로, 기업에서 일할 때에는 언제나 고객 요청 기능 구현이 우선이고, 리팩토링이 팀의 주요 과제가 되는 경우는 드물다고 합니다

  • 다음과 같은 이유로 개인 시간에 하면 좋다고 합니다. 😅 🙄 🤣
`???: 리팩토링은 고객이아니라 개발자에게 좋습니다.
깔끔한 코드는 만족감을 주고, 업무효율을 상승시킵니다.
유행하는 기법을 써보는것도 재밌으며, 포트폴리오에도 이용할 수있어요.`

2장 의미 있는 이름

프로그래머가 가장 많은 시간을 쏟는 행위가 변수명 작성이라는 말이 있습니다.

잘 작성한 이름은 이해 속도는 물론 작성속도까지 높여줍니다.

프로그래머의 뇌 와 비슷한 내용을 이야기하는 거 같아 복습하는 느낌으로 읽었습니다.

의미 있는 이름의 특징

  1. 의도가 분명함
    • 단순하지 않고 서술적임
  2. 발음이 쉬움
    • 협업에 도움을 줌
  3. 검색하기 쉽게 분류가 잘 되어있음
    • 변수를 그룹 지어줌
    • 새 변수를 작성하거나, 변수의 역할을 확인하기 수월함
  4. 인코딩정보나 타입정보는 포함하지 않음
    • 프로그램에서의 사용 맥락 정보만 나타내는 게 좋음
  5. 말장난이 없고, 보편적임
    • 독자의 유추가 필요하지 않은 이름
  6. 도메인 언어를 사용하여 이해가 쉬움
    • 개발자와 프로그램이 이용되는 분야의 종사자 모두 이해하기 쉬운 단어를 사용
  7. 의미 있는 맥락만 소유함
    • 메서드나 프로퍼티에 클래스 이름을 넣는다던지 하는 중복적이고 무의미한 맥락은 제거

단순히 flag 형식의 변수명 (i, j, d) 등은 자제하고 최대한 의도가 잘 드러나는 이름을 사용해야겠습니다.

3장 함수

작고, 한 가지 일을 잘하는 함수를 작성하는 기교들을 소개합니다.

개인적으로 프로그래밍의 작업 단위를 함수로 생각합니다.

작고 한 가지 일을 잘하는 함수를 작성하게 된다면

프로그래밍 개발의 진척도에 대한 메타적 이해도가 높아지지 않을까 생각하며 읽었습니다.

  • 함수형 프로그래밍과는 상관이 없습니다.
    클래스를 작성할 때에도, 일의 단위를 내부 메서드를 몇 개나 구현했느냐로 생각하거든요.

좋은 함수를 작성하는 방법

  1. 작게 만들어야 한다.
    • 작은 함수가 좋은 이유는 무수히 많음 수월한 유지보수, 이해, 가독성..
  2. 블록과 들여 쓰기
    • 들여 쓰기가 2단이 넘어가면 함수가 커짐
  3. 서술적인 이름을 사용
    • 조금 길더라도 자신의 역할을 명확히 설명
    • 다음과 같은 영문장 형식으로 구성 V O C / V O /V O O
  4. 하나의 추상화 수준을 사용
    • 여러 추상화 수준을 건드리면 로직 및 변수명 이해 난도가 상승
    • 한 가지 일을하는데에는 하나의 추상화 수준이 필요
  5. 매개변수는 2개 이하로 구성
    • 이해 및 테스트로직 작성이 수월
    • 애초에 함수가 한가지 일을 하는데에 많은 매개변수가 필요치 않음
    • 들어가는 인수에 따라 기능을 바꾸는 플래그 인수는 구림
      • 하나의 객체 안에 플래그로 사용할 인수를 포함하게 하는 것이 좋음
const inputWithOk = {
    state: "ok",
    contents: "text from api"
}
const inputWithFail = {
    state: "error",
    contents: "error Message"
}

const handleApiResponse = (input) =>{
    const [state, contents ] = input;
    if (state === "ok"){
        renderPage(contents)
    }
    if (state === "error") {
        throwErrorMessage(contents)
    }
}
  1. 부수효과를 배제할 것
    • 함수형 로직을 사용
  2. 반복하지 마라
    • 반복되는 로직을 하나로 묶어 새로운 함수로 분리할 것

함수를 어떻게 짜죠?

저렇게 제약사항이 많아서야, 어떻게 조건을 만족하는 함수를 만들까 생각이 듭니다.

 

하지만 일반적인 작문처럼 함수를 천천히 다듬어가며 완성해 나간다고 합니다.

 

1. 원하는 기능을 수행하는 초안 함수를 구현한다.

2. 단위테스트 로직을 작성한다.

3. 테스트가 망가지지 않는지 확인하며 함수를 천천히 다듬는다.

이야기하고 싶은 것 / 궁금한 것

  1. 이름에 축약어를 사용하지 말것 / 이름에 타입을 사용하지말것
    • 자바는 코딩시점에서 타입을 정하는 정적바인딩 언어입니다.
      그래서 특별한 일이 없으면 저장 타입이 바뀔 일이 없습니다.
      하지만 동적 바인딩 언어에서도 통용되는 규칙이라고 합니다.
      • 프로그래머스 문제: 타입 넣은 매개변수들이 자주 등장
      • 리트코드: 절대 안 넣음
  2. try catch문을 분리하라

try-catch문은 못생겼으니 함수의 바깥으로 분리하라고 합니다.

 

하지만 프로미스 패턴을 사용하는 자바스크립트에서는

현실적으로 적절한 거 같지 않습니다.

 

-얼마전에 읽은글.

setTimeout등과 같은 비동기 코드로 작성한 로직은
외부에서 try-catch 문으로 콜백의 오류를 제어하는것이 불가능합니다.

해결방법은 setTimeout 내부에 try-catch문을 삽입하는것입니다.

 

책의 예제 코드

try {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name.makeKey  ());
    } catch (Exception e) {
    logger.log(e.getMessage());
    }

위의 코드를 분리해서 try - catch문을 분리하라고 합니다.

//분리된 try-catch 로직을 적용한 함수
public void delete(Page page) {
    try {
        deletePageAndAllReferences(page);
        } catch (Exception e) {
        logError(e);
        }
    }

// try-catch를 제거한 함수
private void deletePageAndAllReferences(Page page) throws Exception {
    deletePage(page);
    registry.deleteReference(page.name);
    configKeys.deleteKey(page.name.makeKey());
    }
    private void logError(Exception e) {
    logger.log(e.getMessage());
    }
  1. switch 문을 배제하라 모든 switch문을 부수는 게 더 나은 가시성과 유지보수성을 보장할까요?
    1. switch 문을 배제하고 세 개의 함수로 나누는 것이 과연 더 효율적인가는 좀 의문이 듭니다. 저자도 한 개의 스위치문은 참아준다 합니다. 하지만 참아준다는 것은 결국 쓰면 안된다는 뜻으로 읽힙니다.
  2. 사이드 이펙트를 줄여라
    1. 객체의 안전한 복사, 함수형 프로그래밍 전부 사이드 이펙트를 줄이는 방식입니다.
      배열과 객체의 메서드가 기존의 데이터를 변경하는지, 새로운 것을 생성하는지 잘 분류해 놓읍시다.

 

읽어주셔서 감사합니다.

궁금하신 내용이 있다면 댓글에 남겨주세요.