CS공부(개념)/독후감

클린코드 2주차: 주석, 형식맞추기, 그리고 객체와 자료구조

cantor 2023. 8. 15. 11:39

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

이번주에는 4장 주석, 5장 형식 맞추기, 그리고 6장 객체와 자료구조를 읽고 이야기를 나누기로 했습니다.

4장 주석

첫인상

4장은 신선한 쳅터였습니다.

저는 주석은 코드가 아니라고 생각하고 있었습니다.


그래서 좋은 주석을 작성하는 법에대한 쳅터가
상당히 독특하게 다가왔습니다.

주석은 기껏해야 필요악이다.

저자는 주석을 개발자가 코드로 정확한 의도를 표현하는 것에 대해
실패했을 때 사용하는 필요악으로 묘사합니다.

  • 주석은 거짓말을 한다.

개발자가 코드를 작성할 때 실수를 하는 것처럼,
주석을 작성할 때에도 으레 실수를 합니다.

 

하지만 잘못 쓰인 주석을 테스트할 수 있는 방법은 없으므로
주석은 때로 거짓말을 하거나 혼란을 줍니다.

 

  • 주석은 의무적으로 업데이트되지 않는다.

만약 운 좋게 코드를 간단명료하고 완벽하게 코드를 잘 설명하는
이상적인 주석을 작성하였다고 하더라도 그것은 작성시점의 한시적인 영광일 뿐입니다.

 

세월을 거치고 유지보수를 거치며 코드가 변화하면
주석의 내용은 거짓이 되어버립니다.

시간이 좀 더 흐르면 아무 코드와도 관련이 없는 텍스트상 `고아`로 변모하게 됩니다.

 

그러므로 엉망인 코드를 설명하기 위해 주석을 작성하지 말고,
서술적이고 명료한 이름의 변수와 함수를 가진 코드를 작성합시다.

 

좋은 주석

그럼에도 불구하고 자기가 차지하는 자릿값에 대한 역할을 해내는 주석도 있습니다.

좋은 주석 목록

  1. 법적인주석
    • 저작권정보나 소유권 정보같이 법적인 이유로 의무 기입해야 하는 주석
  2. 정보를 제공하는 주석
  3. 의도를 설명하는 주석
  4. 의미를 명료하게 해주는 주석
    • 직접 짠 로직이 아니라 외부라이브러리를 사용하는 경우에 이용
  5. 결과를 경고하는 주석
  6. TODO 주석
    • 구현이 완료되지 않은 모듈에 남겨놓은 메모
  7. 중요성을 강조하는 주석
    • 특별히 강조해야 하는 포인트를 짚어줌
  8. 공개 API의 주석
    • 해당 API사용자에게 정보를 제공

 

만약 우리가 작성 중인 주석의 목표가 위에 나열된 목록에

포함되지 않는다면 높은 확률로 필요 없는 주석일 것입니다.

 

이 목록들 중에서도 2번과 3번 항목: 정보를 제공하거나 개발자의 의도를 설명하는 주석은
서술적인 코드를 통해 대체할 수 있습니다.

 

나쁜 주석

좋은 주석을 제외한 모든 주석을 일컫는 말입니다.
책의 저자분은 이미 주석은 필요악이라 주장하고,

앞서 드물게 좋은 기능을 하는 주석의 종류도 분류해 놓았습니다.

 

그래서 구태여 나쁜 주석을 파악할 필요가 있나 싶었는데
안티패턴도 따로 정리하고 숙지하여 사용을 회피하는 것처럼

제 주석에 대해 빠른 평가를 내릴 수 있게 하는 의의가 있는 행동이었습니다.

나쁜 주석 목록

  1. 주절거리는 주석
    • 좋은 의도로 작성한 것 같지만, 맥락이 부족하여 타인이 이해할 수 없음
  2. 같은 이야기를 중복하는 주석
    • 변수명이나 함수명으로 표현한 것을 반복 설명하는 주석
  3. 오해할 여지가 있는 주석
  4. 의무적으로 작성하는 주석
    • 모든 함수에 의무적으로 jsDOC을 작성할 필요는 없다
  5. 이력을 관리하는 주석
    • 소스코드 관리시스템이 없을 시절에나 유용
  6. 있으나 마나 한 주석
  7. 닿는괄호에 닫는 주석
    • {} 한 덩어리마다 반복하여 닫는 주석
    • ex } // finish the caclulation
  8. 전역정보
    • 시스템의 전반적인 정보를 기술하는 주석
    • 주석은 주변의 코드를 서술하는 역할을 해야 함
  9. 모호한 관계
    • 주석에 대한 설명이 필요한 주석
  10. 함수헤더
  11. 비공개 코드에서의 jsdoc
    • Jsdoc의 api명세는 공개 라이브러리 코드에만 작성해도 충분함

주석을 없애는 리팩터링

저자의 과거 코드와 리팩터링 코드를 보여줍니다.

  • 과거코드의 특징
    • 굉장히 긴 함수
    • 동작을 들여 쓰기를 이용해 여러 덩어리로 구분지음
    • 덩어리 상단마다 기능설명 주석을 첨부
  • 리팩터링 방식
    • 덩어리를 각각 하나의 메서드로 변경
    • 각 주석의 내용을 해당 메서드의 이름으로 변형하여 이용

5장 형식 맞추기

가독성이 좋은 코드를 생산하기 위한 규칙을 소개합니다.

 

들여 쓰기나 함수로 구분 지어 개념 단위의 혼란을 배제하는 것을 넘어
정말로 독자친화적인 텍스트처럼 코드를 작성하는 방법에 대해 이야기를 들려줍니다.

 

신문기사처럼 작성

제목이나 표제어 같은 중요한 내용을 먼저 기술하고
세부사항은 나중에 기술한다면 코드를 읽는 독자의
이해도를 점진적으로 높일 수 있습니다.

세로형식 맞추기

  1. 개념은 빈행로 구분
    • 서로 다른 동작을 하는 코드사이에는 빈행을 추가
  2. 세로밀집도
    • 비슷하거나 연관도가 높은 코드는 근처에 두어야 함
  3. 변수선언
    • 사용하는 위치에 가깝게 선언
    • 짧은 함수의 경우 맨 위에 선언
  4. 인스턴스 변수 선언
    • 객체 내부에서 사용하게 될 변수의 위치는 모두가 알게끔 약속된 장소에 선언
    • 언어마다 다름: c++은 맨 아래/자바는 맨 위
    • 중요한 것은 모두가 변수의 위치를 아는 것
  5. 수직거리
    • 보통 개념을 구분 짓기 위해 행을 추가
    • 들여 쓰기 없이 붙어있을 때 이해가 수월한 경우도 있음
  6. 세로순서
  • 객체내부 함수가 서로를 호출하는 경우, 호출되는 함수가 나중에 오게 할 것

가로 형식 맞추기

  1. 가로공백과 밀집도
    • 함수와 매개변수괄호사이에는 띄어 쓰지 말 것
    • 산술 연산자를 사용할 때 우선순위가 높은 것은 붙여서, 낮은 것은 띄워서 사용
      • 예시) 1 - 3*5
  2. 선언의 가로정렬
    • 먼저확인해야 하는 것을 강조하는 방법을 사용할 것

그 외

  1. 가짜범위 표시
  • 실행블록이 없는 loop는 세미콜론을 아래줄에 작성
  1. 팀규칙
  • 개인이 선호하는 정렬 규칙은 다양함
  • 팀규칙에 따라 IDE를 설정 후 코딩할 것

 

같이 스터디를 했던 조원분이 항상 협업 시작 전에
서로의 편집기에서 prettier 같은 툴의 설정값을 조율하는 것이 중요하다고 말씀하셨습니다.

 

이 쳅터를 읽으면서 조율 사안에 내놓을만한 구체적인 항목들을 익힐 수 있었습니다.

 

6장 객체와 자료구조

변수를 비공개로 설정하는 방법들에 대한 의의를 검토합니다.


아무래도 이 장을 관통하는 핵심적인 주제는 이것이 아닐까 싶습니다.

 

프로그래밍철학에 따라 클린코드의 스타일도 바뀌지만
해당 프로그래밍 스타일을 엄격하게 따르는 것이 꼭 클린코드로 가는 길은 아니다

변수를 비공개로 설정하는 법

  1. 자료 추상화: 변수를 클래스 내부에 넣고 get과 set으로 접근 가능하게 한다
    • get, set을 만든다고 올바른 추상화는 아님
    • 핵심은 사용자가 구현을 모른 채로 값과 메서드를 사용하는 것
  2. 자료객체/비대칭

본문에서 보여주는 Geometry라는 클래스는
getArea라는 메서드에 여러 종류의 도형객체를 입력받아 넓이를 연산하여 반환합니다.

 

도형의 종류에 따라 넓이를 구하는 법이 다르므로
getAreaif문을 활용하여 절차적으로 도형의 종류를 확인한 후
각 도형에 맞는 계산식으로 넓이를 구합니다.

 

그렇다고 이 절차적인 과정을 없애면 각 도형의 넓이를 계산하는
메서드를 따로 정의해서 넣어줄 도형별 클래스를 각각 만들어주어야 합니다.

이것은 좀더 복잡한 객체 상속관계에대한 정의를 요구합니다.

 

이처럼 절차적인 코드는 새로운 자료구조를 삽입하는 것이,
객체지향적인 코드는 새로운 함수를 삽입하는 것이 어렵습니다.

이것을 이해하고 잘 절충한 코드를 짜야합니다.

  1. 디미터법칙
  • 클래스 C 내부의 메서드 f는 다음과 같은 객체의 메서드만 사용해야 함
    • 클래스 C의 메서드
    • F 내부에서 생성한 메서드
    • F가 인자로 받은 객체가 가진 메서드
    • C의 인스턴스 변수에 저장된 객체
  1. 기차충돌
  • 메서드를 이용해서 map(). filter()와 같이 연쇄적으로 호출하는 것을 자제
  • 중간중간 끊어주어야 함
  • 일반자료구조가 아닌 객체인 경우에는 또 처리방법이 다름
  1. 잡종구조
  2. 구조체 감추기
  3. 자료전달객체 DTO

bean 구조

  • readonly로 선언 후 get으로 가져올 수 있게 하는 사이비 캡슐화

 

 

아무래도 제가 자주 사용하는 스타일이다 보니, 기차 충돌 항목 부분을 주의 깊게 읽었습니다.

 

저는 각 메서드의 반환타입에 해당하는 메서드를 연쇄적으로 사용하는 것이
해당 객체에 대한 이해도를 판단한다고 생각했었습니다.

 

그래서 최대한 메서드체 이닝 집약적인 코드로 문제들을 해결했습니다.

그런데 객체가 아닌 공개자료구조형을 이용할 때에는 별로 좋지 못한 스타일인걸 알았습니다.

 

프로그래머스 코드
//모스부호 문제
const solution = (letter) => letter.split(" ").map(item => morse[item]).join("");

//문자열 내부 중복 문자를 제거하는 문제
const solution = (my_string) => [...my_string].reduce((acc, item) => {
    if (acc.includes(item)) {
        return acc
    }
    acc = [...acc, item]
    return acc

}, []).join("")

스터디 시간에 이야기해 볼 만한 것

  1.   이력을 관리하는 주석은 소스코드 컨트롤 시스템이 없던 시절에 생겼다고 합니다.
    제 생각으로 저희가 접근할 수 있는가 장 흔한 이력관리 툴은 깃 같습니다.
    1. 깃 커밋 컨벤션은 무엇을 사용하거나/ 어떻게 조율해야 할까요.
    2. 어떤 소스코드 컨트롤 시스템을 사용하시나요?
  1. 객체가 다른 객체에게 무엇을 하라고 시키는 행위가 정확히 무엇일까요?
    1. 본문에서 객체는 무엇을 하라고 시켜야지, 자신의 속내 성분을 드러내면 안 된다
      라는 내용이 잘 이해가 가지 않았습니다.
      다른 객체에게 값을 전달하고, 값을 밖으로 드러내지 말라는 뜻으로 이해했는데
      잘 와닿지 않습니다.
      객체 지향의 사실과 오해에서 처럼 다른 객체메서드로 결괏값을 전송하는 것일까요?
  1. 코딩테스트에서 함수단위 모듈화 같은 디테일을 추가할 시 점수를 받을 수 있을까요?