[Java] 자바 코딩 규칙 (Java Code Conventions)

Aiden Shin·2020년 2월 24일
3

Code Conventions


왜 코딩 규칙(Code Convention)이 필요한가?

코딩 규칙은 여러 가지 이유에서 프로그래머에게 중요하다

  • 소프트웨어를 개발하는 일련의 모든 과정에 들어가는 비용 중 80%가 유지보수에 쓰여진다.
  • 소프트웨어의 직접 개발한 개발자가 그 소프트웨어의 유지보수를 담당하는 경우는 거의 보기 힘들다.
  • 코딩 규칙을 지키면 다른 개발자가 그 소스 코드를 처음 보았을 때, 더 빠른 시간 안에 완벽하게 이해할 수 있도록 도와주기 때문에, 소프트웨어의 가독성이 높아진다.
  • 개발자가 자신의 소스 코드를 제품으로 팔려고 한다면, 자신이 작성한 다른 소스 코드들과 잘 어울리도록 패키지(package)를 적절하게 구성할 필요가 있다.

줄 나누기

하나의 식이 한 줄에 들어가지 않을 때에는, 다음과 같은 일반적인 원칙들을 따라서 두 줄로 나눈다.

  • 콤마 후에 두 줄로 나눈다.
  • 연산자(operator) 앞에서 두 줄로 나눈다.
  • 레벨이 낮은 원칙보다는 레벨이 높은 원칙에 따라 두 줄로 나눈다.
  • 앞줄과 같은 레벨의 식(expression)이 시작되는 새로운 줄은 앞줄과 들여쓰기를 일치시킨다.
  • 만약 위의 원칙들이 코드를 더 복잡하게 하거나 오른쪽 끝을 넘어간다면, 대신에 8개의 빈 칸을 사용해 들여쓴다.
    someMethod(longExpression1, longExpression2, longExpression3, 
            longExpression4, longExpression5);
      
    var = someMethod1(longExpression1,
                    someMethod2(longExpression2,
                            longExpression3));

다음은 메서드 선언을 들여쓰는 예제들이다. 첫번째는 일반적인 경우이다. 두번째 예제의 경우 일반적인 들여쓰기를 사용한다면 두번째 줄과 세번째 줄을 들여써야 하므로, 대신에 8개의 빈 칸을 이용하여 들여쓴다.

    // 일반적인 들여쓰기
    someMethod(int anArg, Object anotherArg, String yetAnotherArg,
               Object andStillAnother) {
        ...
    }
      
    // 너무 멀리 들여쓰는 것을 피하기 위해 8개의 빈 칸으로 들여쓰기
    private static synchronized horkingLongMethodName(int anArg,
            Object anotherArg, String yetAnotherArg,
            Object andStillAnother) {
        ...
    }

일반적으로 메서드 본문이 시작할 때 4개의 빈 칸을 사용하므로, 메서드 본문과 구분하기 위해서 줄을 나누는 경우의 들여쓰기는 일반적으로 8개의 빈 칸 원칙을 사용하자 예를 들면 다음과 같다.

    // 아래와 같은 들여쓰기는 사용하지 말자.
    if ((condition1 && condition2)
        || (condition3 && condition4)
        ||!(condition5 && condition6)) { // 좋지 않은 들여쓰기
        doSomethingAboutIt();            // 메서드 본문 시작이 명확하지가 않다.
    } 
      
    // 대신에 아래와 같은 들여쓰기를 사용한다.
    if ((condition1 && condition2)
            || (condition3 && condition4)
            ||!(condition5 && condition6)) {
        doSomethingAboutIt();
    } 
      
    // 또는 아래와 같은 들여쓰기를 사용한다.
    if ((condition1 && condition2) || (condition3 && condition4)
            ||!(condition5 && condition6)) {
        doSomethingAboutIt();
    }

다음은 삼항식(ternary expression)에서 사용 가능한 세 가지 방법이다.

    alpha = (aLongBooleanExpression) ? beta : gamma;  
      
    alpha = (aLongBooleanExpression) ? beta
                                     : gamma;  
      
    alpha = (aLongBooleanExpression)
            ? beta 
            : gamma;

문(Statements)

각각의 줄에는 최대한 하나의 문(statement)만 사용하도록 한다.

    argv++;       // 올바른 사용법
    argc--;       // 올바른 사용법  
    argv++; argc--;       // 이렇게 작성하는 것은 피해라

복합문은 중괄호 “{ statements }” 로 둘러싸여진 문들의 리스트를 포함하는 문이다. 다음 원칙을 따르자.

  • 둘러싸여진 문들은 복합문보다 한 단계 더 들여쓰기를 한다.
  • 여는 중괄호 “{” 는 복합문을 시작하는 줄의 마지막에 위치해야 한다.
  • 닫는 중괄호 “}” 는 새로운 줄에 써야하고, 복합문의 시작과 같은 들여쓰기를 한다.
  • 중괄호들이 if-else 문이나 for 문 같은 제어 구조의 일부분으로 사용되어질 때에는 중괄호들이 모든 문들(단 하나의 문일 경우에도)을 둘러싸는데 사용되어져야 한다(이렇게 사용하는 것이 중괄호를 닫는 것을 잊어버리는 것 때문에 발생하는 버그를 만들지 않고, 문을 추가하는 것에 큰 도움을 준다).

값을 반환하는 return 문은 특별한 방법으로 더 확실한 return 값을 표현하는 경우를 제외하고는 괄호를 사용하지 않는 것이 좋다.

    return;
      
    return myDisk.size();
      
    return (size ? size : defaultSize);

if-else 문을 사용할 때는 다음과 같이 작성한다.

    if (condition) {
        statements;
    }
      
    if (condition) {
        statements;
    } else {
        statements;
    }
      
    if (condition) {
        statements;
    } else if (condition) {
        statements;
    } else {
        statements;
    }
  • if 문은 항상 중괄호를 사용한다. 다음과 같은 에러가 발생할 수 있는 상황은 피해야 한다.
    if (condition) // 이렇게 중괄호 {}를 생략해서 사용하지 말자
        statement;

공백(Blank Spaces)

공백은 다음과 같은 경우에 사용한다.

  • 괄호와 함께 나타나는 키워드는 공백으로 나누어야 한다.
    while (true) {
        ...
    }
  • 메서드 이름과 메서드의 여는 괄호 사이에 공백이 사용되어서는 안 된다는 것을 명심하자. 이렇게 하는 것은 메서드 호출과 키워드를 구별하는데 도움을 준다.
  • 공백은 인자(argument) 리스트에서 콤마 이후에 나타나야 한다.
  • .을 제외한 모든 이항(binary) 연산자는 연산수들과는 공백으로 분리되어져야 한다. 공백은 단항 연산자(++ 혹은 –)의 경우에는 사용해서는 안 된다.
    a += c + d;
    a = (a + b) / (c * d);
     
    while (d++ = s++) {
        n++;
    }
    printSize("size is " + foo + "\n");
  • for 문에서 사용하는 세 개의 식(expression) 들은 공백으로 구분해서 나누어야 한다.
    for (expr1; expr2; expr3)
  • 변수의 타입을 변환하는 캐스트(cast)의 경우에는 공백으로 구분해야 한다.
    myMethod((byte) aNum, (Object) x);
    myMethod((int) (cp + 5), ((int) (i + 3)) + 1);

명명(Naming) 규칙

명명 규칙, 즉 이름을 정하는 규칙은 프로그램을 더 읽기 쉽게 만들어 줌으로써 더 이해하기 쉽게 만들어 준다. 또한 식별자(identifier)를 통해서 기능에 대한 정보도 얻을 수 있다. 예를 들자면, 그것이 상수인지 패키지인지 클래스인지를 알 수 있도록 도와준다. 이러한 정보는 코드를 이해하는데 큰 도움이 된다.

  1. **Packages 명명 규칙은 다음과 같다.**
  • 패키지 이름의 최상위 레벨은 항상 ASCII 문자에 포함되어 있는 소문자로 쓰고, 가장 높은 레벨의 도메인 이름 중 하나이어야 한다.
  • 현재는 com, edu, gov, mil, net, org, 또는 1981년 ISO Standard 316에 명시된 영어 두 문자로 표현되는 나라 구별 코드가 사용된다.
  • 패키지 이름의 나머지 부분은 조직 내부의 명명 규칙을 따르면 된다. 이러한 규칙을 따라 만들어진 이름은 디렉토리 구조에서 디렉토리 이름으로도 사용된다.
  • 예를 들면 부서명, 팀명, 프로젝트명, 컴퓨터 이름, 또는 로그인 이름 등이다. 예제는 다음과 같다.
    com.sun.eng
    
    com.apple.quicktime.v2
    
    edu.cmu.cs.bovik.cheese

2. Classes 명명 규칙은 다음과 같다.

  • 클래스 이름은 명사이어야 하며, 복합 단어일 경우 각 단어의 첫 글자는 대문자이어야 한다.
  • 클래스 이름은 간단하고 명시적으로 작성해야 한다.
  • 완전한 단어를 사용하고 두 문자어와 약어는 피하도록 한다(만약, 약어가 URL이나 HTML과 같이 더 많이 ,더 넓게 사용되고 있다면 약어를 사용하는 것도 괜찮다).
    class Raster;
    class ImageSprite;

3. Interfaces 명명 규칙은 다음과 같다.

  • 인터페이스 이름도 클래스 이름과 같은 대문자 사용 규칙을 적용해야 한다.
    interface RasterDelegate;
    interface Storing;

4. Methods 명명 규칙은 다음과 같다.

  • 메서드의 이름은 동사이어야 하며, 복합 단어일 경우 첫 단어는 소문자로 시작하고 그 이후에 나오는 단어의 첫 문자는 대문자로 사용해야 한다.
    run();
    runFast();
    getBackground();

5. Variables 명명 규칙은 다음과 같다.

  • 변수 이름의 첫 번째 문자는 소문자로 시작하고, 각각의 내부 단어의 첫 번째 문자는 대문자로 시작해야 한다.
  • 변수 이름이 언더바 (_) 또는 달러 표시 문자로 시작하는 것이 허용되기는 하지만, 이 문자들로 시작하지 않도록 주의하자.
  • 이름은 짧지만 의미 있어야 한다.
  • 이름의 선택은 그 변수의 사용 의도를 알아낼 수 있도록 의미적이어야 한다.
  • 한 문자로만 이루어진 변수 이름은 암시적으로만 사용하고 버릴 변수일 경우를 제외하고는 피해야 한다.
  • 보통의 임시 변수들의 이름은 integer 일 경우에는 i, j, k, m, n을 사용하고, character 일 경우에는 c, d, e를 사용한다.
    intcharfloat

6. Constants 명명 규칙은 다음과 같다.

  • 클래스 상수로 선언된 변수들과 ANSI 상수들의 이름은 모두 대문자로 쓰고 각각의 단어는 언더바("_")로 분리 해야 한다.
  • 디버깅을 쉽게 하기 위해서 ANSI 상수들의 사용은 자제하도록 한다.
    int i;
    char c;
    float myWidth;

좋은 프로그래밍 습관

  1. 인스턴스 변수와 클래스 변수를 외부에 노출하지 말고 대신 접근을 제공
    • 인스턴스 변수 또는 클래스 변수를 합당한 이유없이 public으로 선언하지 말자. 인스턴스 변수들은 명시적으로 선언될 필요가 없는 경우가 많다.
    • 인스턴스 변수가 public으로 선언되는 것이 적절한 경우는 클래스 자체가 어떤 동작(behavior)을 가지지 않는 데이터 구조일(data structure) 경우이다. 다시 말해서 만약 class 대신 struct를 사용해야 하는 경우라면(만약 Java가 struct를 지원한다면) class의 인스턴스 변수들을 public으로 선언하는 것이 적합하다.

2. 클래스 변수와 클래스 메서드는 클래스 이름을 사용하여 호출

  • 클래스(static) 변수 또는 클래스 메서드를 호출하기 위해서 객체를 사용하는 것을 피해야 한다. 대신에 클래스 이름을 사용해라.
    classMethod();             // 좋은 사용법
    AClass.classMethod();      // 좋은 사용법
    anObject.classMethod();    // 나쁜 사용법

3. 숫자는 바로 사용하지 않고 선언해서 변수 이름으로 접근

  • 숫자 상수는 카운트 값으로 for 루프에 나타나는 -1, 0, 1을 제외하고는 숫자 자체를 코드에 사용하지 말자.

4. 변수에 값을 할당할 때 주의할 것들

  • 하나의 문(statement)에서 같은 값을 여러 개의 변수들에 할당하지 말자(이렇게 하면 읽기가 어렵게 된다)
    fooBar.fChar = barFoo.lchar = 'c'; // 이렇게 사용하지 말자
  • 비교 연산자(equality operator: ==)와 혼동되기 쉬운 곳에 할당 연산자(assignment operator: =)를 사용하지 말자.
    // 이렇게 사용하지 말자 (자바가 허용하지 않음)
    if (c++ = d++) {
        ...
    }
    
    // 다음과 같이 써야 한다
    if ((c++ = d++) != 0) {
        ...
    }
  • 실행시 성능 향상을 위해서 할당문(assignment statement)안에 또 다른 할당문을 사용하지 말자.
    // 이렇게 사용하지 말자
    d = (a = b + c) + r;
    
    // 다음과 같이 써야 한다
    a = b + c;        
    d = a + r;

5. 그 외 신경써야 할 것들

  • 괄호

연산자 우선순위 문제를 피하기 위해서 복합 연산자를 포함하는 경우에는 자유롭게 괄호를 사용하는 것이 좋은 생각이다(작성자는 연산자 우선 순위를 확실하게 알고 있다고 할지라도, 다른 프로그래머에게는 생소할 수 있다는 것을 기억하자).

    if (a == b && c == d)     // 이렇게 사용하지 말자
    if ((a == b) && (c == d)) // 이렇게 사용하자
  • 반환 값

프로그램의 구조와 목적이 일치해야 한다.

    // 이렇게 사용하지 말자
    if (booleanExpression) {
        return true;
    } else {
        return false;
    }
    
    // 다음과 같이 써야 한다
    return booleanExpression;
    // 이렇게 사용하지 말자
    if (condition) {
        return x;
    }
    return y;
    
    // 다음과 같이 써야 한다
    return (condition ? x : y);
  • 조건 연산자 ‘?’ 이전에 나오는 식(expression)

삼항 연산자(ternary operator - ? : ) 에서 ? 이전에 이항 연산자(binary operator)를 포함하는 식(expression)이 있는 경우에는, 꼭 괄호를 사용해야 한다.

    (x >= 0) ? x : -x;
profile
예전 블로그: https://shinilhyun.github.io/

2개의 댓글

comment-user-thumbnail
2022년 8월 25일

감사합니다

답글 달기
comment-user-thumbnail
2023년 12월 14일

언젠가 한번 정리해야지.. 했던 내용인데 감사합니다!

답글 달기