min's devlog
Java 코드 컨벤션 본문
본 포스팅의 원문은 Java가 Oracle에 인수되기 전인 1999년도에 Sun에서 작성된 Code Conventions이다. 자바를 공부하고 팀 프로젝트를 거치며 코드를 짜는 일정한 패턴을 가지는 것의 중요성을 느꼈다. 나 이외의 다른 사람이 작성한 코드를 한 눈에 알아보기 어려운 경우도 있었고, 한 프로젝트를 진행하며 서로의 스타일이 다르니 직접 물어가며 소스를 합치고 고치는 작업도 꽤 많은 시간이 소요되었기 때문이다.
원문은 영어이며, 스스로 코드 규칙을 지키고 앞으로도 공부하며 참고하고자 포스팅을 하게 되었다. (영어공부를 겸해 직접 원문을 보며 해석한 부분도 있고 다른 이의 해석을 참고한 부분도 있다.)
코드 컨벤션이 필요한 이유
- 소프트웨어를 개발하는 일련의 모든 과정에 들어가는 비용 중 80%가 유지보수에 쓰여진다.
- 소프트웨어의 개발자가 그 소프트웨어의 유지보수까지 담당하는 경우는 드물며, 다른 개발자들의 코드 이해를 돕기 때문에 소프트웨어의 가독성이 높아진다.
자바 파일 구조
- 파일은 주석을 통해 다른 구역으로 나누어진다.
- 2,000 라인을 넘는 파일은 이해하기 쉽지 않기 때문에 피해야한다.
자바 소스 파일
- 각각의 자바 소스 파일은 public 클래스/인터페이스를 가진다.
- public 클래스는 파일에서 첫 번째 클래스/인터페이스 여야 한다.
* 자바 소스 파일의 순서
시작 주석
Package 문과 Import 문
Class와 Interface 선언
/*
* 클래스 이름
*
* 버전 정보
*
* 날짜
*
* 저작권 주의
*/
package java.awt;
import java.awt.peer.CanvasPeer;
들여쓰기
- 4개의 빈 칸을 들여쓰기 단위로 사용한다.
- 8개의 빈 칸을 들여 tab으로 사용한다.
한줄의 길이
- 한 줄에 80자 이상 쓰는 것은 대부분의 터미널과 툴에서 다룰 수 없기에 피해야한다.
줄 나누기
- 하나의 식이 한 줄에 들어가지 않는다면, 다음 원칙을 통해 두 줄로 나눈다.
* 콤마 후에 두 줄로 나눈다.
* 연산자 앞에서 두 줄로 나눈다.
* 레벨이 높은 원칙에 따라 두 줄로 나눈다.
* 앞 줄과 같은 레벨의 식이 시작되는 새로운 줄은 앞줄과 들여쓰기를 일치시킨다.
* 위의 원칙들이 코드를 더 복잡하게 한다면, 대신 8개의 빈칸을 사용해 들여쓰기한다.
someMethod(longExpression1, longExpression2, longExpression3,
longExpression4, longExpression5);
var = someMethod1(longExpression1,
someMethod2(longExpression2,
longExpression3));
longName1 = longName2 * (longName3 + longName4 - longName5)
+ 4 * longname6; // 될 수 있으면 이 방법을 사용한다.
longName1 = longName2 * (longName3 + longName4
- longName5) + 4 * longname6; // 될 수 있으면 피한다.
주석
- 자바 프로그램은 두 가지 종류의 주석을 가진다.
* 구현 주석
- /*...*/ 와 // 에 의해 경계가 정해지는 C++과 동일하다.
- 각각의 구현에 대한 추가적인 설명이 필요할 때 쓰인다.
* 문서화 주석
- /**...*/에 의해 경계가 결정된다.
- 소스 코드가 없는 개발자들도 읽고 이해할 수 있도록 소스의 specification을 포함한다.
구현 주석
- 구현 주석은 4가지로 나눌 수 있다.
1. 블록 주석
- 파일, 메서드, 자료구조, 알고리즘에 대한 설명을 제공할 때 사용한다.
- 주석이 설명하는 코드와 같은 단위로 들여쓰기 해야한다.
- 다른 코드들과 구분하기 위해 처음 한 줄은 비우고 사용한다.
/*
* 여기에 블록 주석을 작성
*/
2. 한줄 주석
- 한 줄 주석은 빈 줄로 시작된다.
if (condition){
/* 이 조건을 만족하면 실행된다. */
...
}
3. 꼬리 주석
- 아주 짧은 주석이 필요할 경우 주석이 설명하는 코드와 같은 줄에 작성한다.
- 실제 코드와 구분하도록 충분히 멀리 떨어뜨려야한다.
if (a==5) {
return TRUE; /* 특별한 경우 */
} else {
return FALSE; /* 그 외의 경우 */
}
4. 줄 끝 주석
- // 는 한 줄 모두를 주석 처리하거나, 한 줄의 일부분을 주석 처리해야 할 때 사용 가능하다
문서화 주석
- 문서화 주석은 다음 5가지를 설명한다.
* 자바 클래스
* 인터페이스
* 생성자
* 메서드
* 필드
- 각각의 문서화 주석은 /**...*/ 안으로 들어간다.
- 문서화 주석은 선언 바로 전에 나와야 한다.
한 줄당 선언문의 수
- 한 줄에 하나의 선언문을 쓰는 것이 좋다. (주석문 쓰는 것을 쉽게 해주기 때문이다)
int level;
int size; // 좋은 예시
int level, size; // 안 좋은 예시
int foo, fooarray[]; // 금지
클래스와 인터페이스의 선언
- 메서드 이름과 그 메서드의 파라미터 리스트의 시작인 "(" 사이에 공백을 두지 않는다.
- 여는 중괄호 "{" 는 클래스/인터페이스/메서드 선언과 동일한 줄의 끝에 사용한다.
- 닫는 중괄호 "}" 는 여는 문장과 동일한 들여쓰기를 하는 새로운 줄에 사용한다.
- 메서드들을 구분하기 위해서 각 메서드들 사이에는 한 줄을 비운다.
복합문
- 둘러싸인 문들은 복합문보다 한 단계 더 들여 쓰기 한다.
- 여는 중괄호 "{" 는 복합문을 시작하는 줄의 마지막에 위치한다.
- 닫는 중괄호 "}"는 새로운 줄에 써야 하며, 복합문 시작 줄 만큼 들여 쓰기 한다.
- 중괄호들이 제어 구조의 일부분으로 사용될 때는 중괄호들이 모든 문들을 둘러싸는데 사용되어야한다.
return 문
- 특별히 더 확실한 return 값을 표현하는 경우 제외하고는 괄호를 사용하지 않는 것이 좋다.
return;
return myDisk.size();
return (size ? size : defaultSize);
if-else문
- if-else문은 다음과 같이 사용한다.
if (condition) {
statements;
} else if (condition) {
statements;
} else {
statements;
}
for문
- for문은 다음과 같이 사용한다.
for (initialization; condition; update) {
statements;
}
while, do-while문
- while, do-while문은 다음과 같이 사용한다.
while (condition) {
statements;
}
do {
statements;
} while (condition);
switch문
- switch문은 다음과 같이 사용한다.
- 모든 switch문은 default case를 포함하도록 한다.
- 어떤 경우에 default case에서 break는 중복적이지만, 이후에 또 다른 case가 추가될 경우 에러를 방지할 수 있다.
switch (condition) {
case ABC:
statements;
/* 다음줄로 계속 진행한다. */
case DEF:
statements;
break;
case XYZ:
statements;
break;
default:
statements;
break;
}
try-catch문
- try-catch문은 try 블록이 성공적으로 완료되든지, 아니면 중간에 에러가 발생하든지에 상관없이 실행되어야 하는 부분을 추가하기 위해서 finallly 부분을 사용할 수 있다.
try {
statements;
} catch (ExceptionClass e) {
statements;
}
try {
statements;
} catch (ExceptionClass e) {
statements;
} finally {
statements;
}
한 줄 띄우기
- 한 줄 띄우고 코드를 작성해 가독성을 높인다.
- 다음과 같은 경우 한 줄 띄도록 한다.
* 메서드들 사이에서
* 메서드 안의 지역 변수와 그 메서드의 첫 문장 사이에서
* 블록 주석 또는 한 줄 주석 이전에
* 가독성을 향상하기 위한 메서드 내부의 논리적인 섹션들 사이에
- 다음의 경우 두 줄 띄고 작성한다.
* 소스 파일의 섹션들 사이에서
* 클래스와 인터페이스 정의 사이에서
명명 규칙 (Naming)
- 프로그램을 더 읽기 쉽게 만들어준다. 또한 식별자를 통해서 기능에 대한 정보도 얻을 수 있다.
* Packages
* Classes
* Interfaces
* Methods
* Variables
* Constants
1. Packages
- 패키지 이름의 최상위 레벨은 항상 ASCII 문자에 포함되어 있는 소문자로 쓰고, 가장 높은 레벨의 도메인 이름 중 하나이어야 한다.
- 패키지 이름의 나머지 부분은 조직 내부의 명명 규칙을 따르면 된다. (디렉토리 구조에서 디렉토리 이름으로도 사용됨)
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();
getBackgrond();
5. Variables
- 변수 이름의 첫 문자는 소문자로 시작하고, 각각 내부 단어의 첫 문자는 대문자로 시작해야 한다.
- 변수 이름이 언더바(_) 또는 달러 문자로 시작하는 것이 허용되나, 이 문자들로 시작하지 않도록 주의하자.
- 이름은 짧지만 의미있어야한다.
- 이름의 선택은 그 변수의 사용 의도를 알아낼 수 있도록 의미적이어야한다.
- 한 문자로만 이루어진 변수 이름은 암시적으로만 사용한다.
- 보통의 임시 변수들의 이름은 integer 일 경우에는 i, j, k, m, n을 사용하고, character 일 경우에는 c, d, e를 사용한다.
int i;
char c;
float myWidth;
6. Constants
- 클래스 상수로 선언된 변수들과 ANSI 상수들의 이름은 모두 대문자로 쓰고, 각각의 단어는 "_" 로 분리한다.
static final int MIN_WIDTH = 4;
static final int MAX_WIDTH = 999;
그 외 신경써야 할 것들
- 괄호
연산자 우선순위 문제를 피하기 위해 복합 연산자를 포함하는 경우에는 자유롭게 괄호를 사용해도 좋다.
if (a == b && c == d) //올바르지 않은 괄호 사용
if ((a == b) && (c == d)) //올바른 괄호 사용
- 반환 값
프로그램의 구조와 목적이 일치해야 한다.
//올바르지 않은 반환값 사용
if (booleanExpression) {
return true;
} else {
return false;
}
//올바른 반환값 사용
return booleanExpression;
코드 예제
- public class를 가지는 소스 파일을 어떻게 수정하는지 보여준다.
/*
* @{#}CodeConvention.java 0.82 2022/05/30
*
* [저작권 및 라이센서 관련 정보를 여기에 작성한다.]
* Copyright (c) 1993-1996 Sun Microsystems, Inc. All Rights Reserved.
*
* This software is the confidential and proprietary information of Sun
* Microsystems, Inc. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Sun.
*/
package java.blah;
import java.blah.blahdy.BlahBlah;
/**
* 클래스에 대한 설명을 여기에 작성한다.
*
* @version 1.10 04 Oct 1996
* @author Firstname Lastname
*/
public class Blah extends SomeClass {
/* 클래스의 구현 주석을 여기에 작성한다. */
/** 클래스 변수 classVar1에 대한 설명을 여기에 작성한다. (문서 주석) */
public static int classVar1;
/**
* 클래스 변수 classVar2에 대한 설명이 (문서 주석)
* 한 줄 이상일 경우 이렇게 작성한다. (접근 제어자가 private일 경우 나오지 않는다.)
*/
private static Object classVar2;
/** 인스턴스 변수 instanceVar1에 대한 설명을 여기에 작성한다. (문서 주석) */
public Object instanceVar1;
/** 인스턴스 변수 instanceVar2에 대한 설명을 여기에 작성한다. (문서 주석) */
protected int instanceVar2;
/** 인스턴스 변수 instanceVar3에 대한 설명을 여기에 작성한다. (문서 주석) 접근 제어자가 private일 경우 나오지는 않음. */
private Object[] instanceVar3;
/**
* ... 생성자 CodeConvetion()에 대한 설명을 여기에 작성한다. (문서 주석) ...
*/
public Blah() {
// ... 여기에 실제 코드를 작성한다. ...
}
/**
* ... 메서드 doSomething()에 대한 설명을 여기에 작성한다. (문서 주석)...
*/
public void doSomething() {
// ... 여기에 실제 코드를 작성한다. ...
}
/**
* ... 메서드 doSomethingElse()에 대한 설명을 여기에 작성한다. (문서 주석) ...
* @param someParam 파라미터에 대한 설명
* @return String 리턴값에 대한 설명
* @exception exception 예외사항에 대한 설명
*/
public String doSomethingElse(Object someParam) {
// ... 여기에 설계 코드를 작성한다. ...
}
}
'Other efforts' 카테고리의 다른 글
OSI와 TCP/IP (0) | 2022.06.12 |
---|---|
Git (0) | 2022.06.03 |
Design Pattern(2) (0) | 2022.05.27 |
Design Pattern (0) | 2022.05.17 |
아이디어 디벨롭 (0) | 2021.05.11 |