Group Study (2021-2022)/Clean Code

[클린코드 북리뷰 스터디] 2주차 - 주석, 형식 맞추기

알 수 없는 사용자 2022. 5. 20. 19:47

4장. 주석

나쁜 코드에 주석을 달지 마라. 새로 짜라 _ 브라이언 W.. 커니핸, P.J. 플라우거

 

주석은 나쁜 코드를 보완하지 못한다.

코드에 주석을 추가하는 일반적인 이유는 코드의 품질이 나쁘기 때문이다. 표현력이 풍부하고 깔끔하며 주석이 거의 없는 코드가, 복잡하고 어수선하며 주석이 많이 달린  코드보다 훨씬 좋다.
주석은 코드의 변화에 따라가지 못하고, 방치된다. 코드는 컴파일되어 관리되지만, 주석은 그저 주석이기 때문에 그 자리에 방치되고 결국 의미 없는 텍스트가 되어버리게 되는 것이다.
따라서, 나쁜 코드를 주석으로 설명하려고하지 말고, 코드를 개선하는데 시간을 보내야 한다! 코드로도 의도를 표현할 수 있다!

//직원에게 복지 혜택을 받을 자격이 있는지 검사한다.
if ((employee.flags & HOURLY_FLAG) && (employee.age >65))

if (employee.isEligibleForFullBenefits())

코드만으로 의도를 표현하기 어려운 경우도 물론 존재하지만, 그래도 코드로 의도를 대부분 표현할 수 있다.


좋은 주석

1) 법적인 주석

때로는 회사가 정립한 구현 표준에 맞춰 법적인 이유로 특정 주석을 넣으라고 명시한다. 예를 들면, 각 소스 파일 첫머리의 주석으로 들어가는 저작권 정보나 소유권 정보가 될 수 있다.

//Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
//GNU General Public License 버전 2 이상을 따르는 조건으로 배포한다.

 

2) 정보를 제공하는 주석

때로는 기본적인 정보를 주석으로 제공하면 편리하다. 가능하다면 함수 이름에 정보를 적는 것이 좋다.

//kk:mm:ss EEE, MMM dd, yyyy 형식
Pattern timeFormat=Pattern.compile("\\d*:\\d:\\d* \\w*, \\w* \\d* \\d*");

 

3) 의도를 설명하는 주석

현업에서 자주 사용하는 주석이라고 볼 수 있다.

//스레드를 많이 생성하여 시스템에 영향을 미쳐 테스트를 만들도록 함
for (int i=0; i<25---; i++){
  SomeThread someThread=ThreadBuilder.builder().build();
 }
 
//유저로부터 입력받을 값을 저장할 때 trim으로 공백제거가 필요
String userName=userNameInput.trim();

 

 

4) TODO와 FIXME 주석

TODO: 앞으로의 할일, 지금은 해결하지 않지만 나중에 해야 할 일을 미리 적어둘 때 사용하는 주석

FIXME: 문제가 있지만, 당장은 수정할 필요가 없을때, 가능하면 빨리 수정하는 것이 좋다.

 

5) 의미를 명료하게 밝히는 주석

때때로 모호한 인수나 반환값은 그 의미를 읽기 좋게 표현하면 이해하기 쉽다. 

assertTrue(a.compareTo(a) == 0); //a == a
assertTrue(a.compareTo(b) != 0); //a != b
assertTrue(ab.compareTo(ab) == 0); //ab == ab
assertTrue(a.compareTo(b) == -1); //a<b

그러나, 그릇된 주석을 달아둘 위험이 있기 때문에, 의미를 명료하게 밝히는 주석의 경우 필요한 동시에 주석이 위험하게 될 수 있다. 따라서, 이 경우 더 나은 방법이 없는지 고민하고 주석을 달아야 한다.

 

6) 결과를 경고하는 주석

다른 프로그래머에게 결과를 경고할 목적으로 주석을 사용한다. 아래의 예시는 특정 테스트 케이스를 꺼야 하는 이유를 설명하는 주석이다.

// 여유시간이 충분하지 않다면 실행하지 마세요.
public void _testWithReallyBigFile(){
writeLinesToFile(100000000);

response.setBody(testFile);
response.readyToSend(this);
String responseString=output.toString();
assertSubString("Content_length: 1000000000", responseString);
assertTrue(bytesSent > 1000000000);
}

 

 

7) 중요성을 강조하는 주석

자칫 대수롭지 않다고 여겨질 것의 중요성을 강조하기 위해서 주석을 사용하기도 한다.

 

8) 공개 API에서 Javadocs

표준 자바 라이브러리에서 사용한 Javadocs가 대표적인 예이다. JavaDoc은 Java 코드에서 API 문서를 html 방식으로 생성해주는 도구라고 볼 수 있다.

// this is a single line comment

/*
* this is a regular multi-line comment
*/

/**
* this is a javadoc
*/
  • @link: link의 클래스로 바로 연결된다.
  • <p>와 같은 html 문법을 사용 가능하다.
  • @param: method인자에 대한 설명
  • @return: 결괏값을 전달해주는 설명

 

주석보다 annotation

annotation은 코드에 대한 메타데이터로 코드의 실행 흐름에 간섭을 주기도 하고, 주석처럼 코드에 대한 정보를 줄 수 있다.

  • @Deprecated: 컴파일러가 warning을 발생시키며, IDE에서 사용 시에 표시된다.
  • @NotThreadSafe: Thread가 Safe하지 않음을 의미한다.

5장. 형식 맞추기

형식을 맞추는 목적

코드 형식은 의사소통의 일환이다. 의사소통은 전문 개발자의 일차적인 의무이다. 즉 형식을 맞추는 목적은 가독성에 필수적이기 때문이다.

  • 코드를 수월하게 읽어갈 수 있으며, 아마추어처럼 보이지 않는다.
  • 포맷팅으로 인해 코드를 잘못 해석하여 버그가 발생할 위험을 줄인다.

적절한 행 길이를 유지하라

 

파일 길이 분포, 로그 배율

프로젝트 7개의 최대 파일 길이와 최소 파일 길이를 조사한 것이다. 이를 통해, 500줄을 넘지 않고 대부분 200줄 정도의 파일로도 커다란 시스템을 구축할 수 있다는 것을 확인할 수 있다. 반드시 지켜야 하는 규칙은 아니나, 일반적으로 큰 파일보다 작은 파일이 더 이해하기 쉽기 때문에 바람직한 규칙이라고 생각하면 된다.

  • 신문기사처럼 작성하라

    이름은 간단하면서도 설명이 가능하도록 짓는다. 이름만 보고도 올바른 모듈을 살펴보고 있는지 아닌지를 판단할 수 있도록 신경 써서 짓는다. 소스 파일 첫 부분은 고차원 개념과 알고리즘을 설명하고, 아래로 내려갈수록 의도를 세세하게 표현한다.

  • 개념은 빈 행으로 분리하라

    일련의 행 묶음은 완결된 생각 하나를 표현하기 때문에 개념은 빈 행으로 구분한다. 즉, 패키지 선언부, import문, 각 함수 사이에 빈 행을 넣어준다.
형식이 맞춰진 ex)

package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {
    public static final String REGEXP="'''.+?'''";
    private static final Pattern pattern=Pattern.compile("'''(.+?)'''",
    	Pattern.MULTILINE+Pattern.DOTALL
    );

    public BoldWidget(ParentWidget parent, String text) throws Exception{
        super(parent);
        Matcher match=pattern.matcher(text);
        match.find();
        addChildWidgets(match.group(1));
    }

    public String render() throws Exception{
        StringBuffer html=new StringBuffer("<b>");
        html.append(childHtml()).append("</b>");
        return html.toString();
    }
}
형식이 맞춰지지 않은 ex)

package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
    public static final String REGEXP="'''.+?'''";
    private static final Pattern pattern=Pattern.compile("'''(.+?)'''",
    	Pattern.MULTILINE+Pattern.DOTALL
    );
    public BoldWidget(ParentWidget parent, String text) throws Exception{
        super(parent);
        Matcher match=pattern.matcher(text);
        match.find();
        addChildWidgets(match.group(1));
    }
    public String render() throws Exception{
        StringBuffer html=new StringBuffer("<b>");
        html.append(childHtml()).append("</b>");
        return html.toString();
    }
}

 

  • 세로 밀집도

    줄 바꿈이 개념을 분리한다면, 세로 밀집도는 연관성을 의미한다. 즉, 서로 밀접한 코드 행은 세로로 가까이에 놓여야 한다.

  • 수직 거리

    서로 밀접한 개념은 세로로 가까이에 두어야 한다. 같은 파일에 속할 정도로 밀접한 두 개념은 세로 거리로 연관성을 표현한다. 여기에서의 연관성은 한 개념을 이해하는데 다른 개념이 중요한 정도이다.

    1) 변수 선언: 변수는 사용하는 위치에 최대한 가까이 선언한다.
    2) 인스턴스 변수: 클래스 맨 처음에 선언한다. 변수 간에 세로로 거리를 두지 않는다.
    3) 종속 함수: 한 함수가 다른 함수를 호출 시, 두 함수는 세로로 가까이에 배치한다. 호출하는 함수를 먼저 배치
    4) 개념적 유사성: 개념적 친화도가 높을수록 코드를 가까이에 배치한다.
       친화도는 한 함수가 다른 함수를 호출해 생기는 직접적인 종속성이 한 예이다. 
       명명법이 똑같고 기본 기능이 유사하고 간단하면 종속적 관계가 없더라도 가까이에 배치해야 할 함수이다.

  • 세로 순서

    일반적으로 함수 호출 종속성은 아래 방향으로 유지한다. 즉, 호출되는 함수를 호출하는 함수보다 나중에 배치한다. 그러면 소스코드 모듈이 고차원에서 저차원으로 자연스럽게 내려가게 된다.

가로 형식 맞추기

 

자바 행길이 분포

위에서 파일 길이를 살펴본 프로젝트 7개의 행길이를 조사한 분포이다. 그 결과, 20자에서 60자 사이인 행이 총 행의 수의 40%에 달한다. 이 책의 저자는 120자 정도로 행 길이를 추천한다.

  • 가로 공백과 밀집도

    가로로는 공백을 사용하여 밀접한 개념과 느슨한 개념을 표현한다.

  • 들여 쓰기

    소스파일은 윤곽도와 계층이 비슷하다. 파일 전체에 적용되는 정보, 파일 내 개별 클래스에 적용되는 정보, 클래스 내 각 메서드에 적용되는 정보, 블록 내 블록에 재귀적으로 적용되는 정보가 있다. 이렇게 범위로 이뤄진 계층을 표현할 때 들여 쓰기를 사용한다.

Java Class Declarations

Class 내부 코드 순서)

  • static 변수: public -> protected -> package -> private
  • instance 변수 : public -> protected -> package -> private
  • 생성자
  • 메서드: public 메서드에서 호출되는 private 메서드는 그 아래에 둔다. 가독성 위주로 그룹핑한다.


팀 규칙

팀은 한 가지 규칙에 합의해야 하고, 팀원들은 그 규칙을 따른다. 그래야 소프트웨어가 일관적인 스타일을 보인다.

좋은 소프트웨어 시스템은 읽기 쉬운 문서로 이뤄지며, 스타일은 일관적이고 매끄러워야 한다.

개발 언어의 컨벤션이 우선이지만, 애매한 부분은 팀의 컨벤션을 따른다. 없다면 함께 만들어가는 것이 좋다.

(참고할만한 컨벤션) google java style guide, naver hackday java convention


+) 참고자료
책) Clean Code(클린 코드) 애자일 소프트웨어 장인 정신

강의) 제로베이스 한달한권 클린코드