Code Conventions(코딩 규칙)을 왜 알아야 할 까 ?
개발하는 과정 속에서 구현하는 비용보다 유지보수의 비용이 더 크게 들어가는데
프로젝트나 소프트웨어 개발을 하면서 작성한 코드를 나만 보는 것이 아니라 참여한 모든 개발자들이 보게 됩니다.
하지만 나만의 방식으로 코드를 짰다면 다른 사람들이 봤을 때 이해하기가 힘들겠죠.
예를 들자면 나만의 독특한 글씨체로 글을 쓴 편지를 친구에게 보냈는데 그 친구가 그 편지를 읽는데에 해독이 필요한 것처럼요.
그래서 Code Conventions이 필요합니다.
정해진 Code Conventions에 맞춰 코드를 작성하게 된다면 나 외의 다른 사람들도 코드를 해석하는데 빠르게 이해할 수 있어 지게 되므로 가독성이 좋아지게 됩니다.
이 포스팅에서 설명할 컨벤션 규칙은 NAVER CAMPUS HACKDAY의 규칙을 참고하여 작성하였습니다.
인텔리제이에 Java Code Conventions을 적용할 수 있는데 여기를 참고하시는 것을 추천 드립니다.
파일 공통 요건
파일 인코딩은 UTF-8
- 인텔리제이 Encoding 설정
인텔리제이의 경우 Help -> Edit Custom VM Options을 클릭한 후, -Dfile.encoding=UTF-8 를 추가해준 후 저장해줍니다.
- 인텔리제이 파일 인코딩 설정
File -> Settings -> Editor -> File Encodings -> Global, Project Encoding, Properties Files 설정을 UTF-8로 변경
새줄 문자는 LF
파일의 마지막에 개행 추가 (newline)
File -> Settings -> Editor -> General
이름 (Naming)
식별자에는 영문/숫자/언더스코어만 허용한다.
변수명, 클래스명, 메서드명 등에는 영어와 숫자만을 사용한다.
상수에는 단어 사이의 구분을 위하여 언더스코어(_)를 사용한다.
식별자의 이름을 한국어 발음대로 영어로 옮겨 표기하지 않는다.
- 나쁜 예 : moohyungJasan (무형자산)
- 좋은 예 : intangibleAssets (무형자산)
패키지 이름은 소문자로 구성한다.
단어별 구문을 위해 언더스코어(_)나 대문자를 섞지 않는다.
- 나쁜 예
package com.navercorp.apiGateway
package com.navercorp.api_gateway
- 좋은 예
package com.navercorp.apigateway
클래스/인터페이스 이름에 대문자 카멜표기법 적용한다.
클래스 이름은 단어의 첫 글자를 대문자로 시작하는 대문자 카멜표기법(Upper camel case)을 사용한다.
- 나쁜 예
public class reservation
public class Accesstoken
- 좋은 예
public class Reservation
public class AccessToken
클래스 이름과 에 인터페이스 이름에 명사를 사용한다.
클래스 이름은 동사가 아닌 명사나 명사절로 짖는다.
인터페이스(interface)의 이름은 클래스 이름은 명사/명사절로 혹은 형용사/형용사절로 짓는다.
테스트 클래스는 "TEST"로 끝난다.
JUnit 등으로 작성한 테스트 코드를 담은 클래스의 이름 마지막에 "Test"을 붙인다
public class ValidatorTest {
메서드 이름과 변수에는 소문자 카멜표기법을 적용한다.
첫 번째 단어를 소문자로 작성하고, 이어지는 단어의 첫 글자를 대문자로 작성하는 소문자 카멜표기법(Lower camel case)를 사용한다.
테스트 클래스의 메서드 이름에서는 언더스코어를 허용한다.
- 메서드
getSize();
printBridgeResult();
- 변수
private boolean authorized;
private int accessToken;
메서드의 이름은 동사/전치사로 시작한다.
메서드명은 기본적으로는 동사로 시작한다.
다른 타입으로 전환하는 메서드나 빌더 패턴을 구현한 클래스의 메서드에는 전치사를 쓸 수 있다.
- 동사 사용 : renderHtml()
- 전환 메서드의 전치사 : toString()
- Builder 패턴 적용한 클래스의 메서드의 전치사 : withUserId(String id)
상수는 대문자와 언더스코어로 구성한다.
"static final"로 선언되어 있는 필드일 때를 상수로 간주한다.
상수 이름은 대문자로 작성하며, 복합어는 언더스코어 ' _ ' 를 사용하여 단어를 구분한다.
public final int LOTTO_MIN_RANGE = 1;
public final int LOTTO_MAX_RANGE = 45;
public final String BUY_LOTTO_INPUT = “구입할 로또 개수를 입력해주세요”;
임시 변수 외에는 1 글자 이름 사용 금지한다.
변수의 이름에는 1글자로 된 이름을 쓰지 않는다.
반복문의 인덱스나 람다 표현식의 파라미터 등 짧은 범위의 임시 변수에는 관례적으로 1글자 변수명을 사용할 수 있다.
HtmlParser p = new HtmlParser(); // X
HtmlParser parser = new HtmlParser(); // O
선언
클래스, 필드, 메서드, 변수값, import문 등의 소스 구성요소를 선언할 때 고려해야할 규칙이다.
소스파일당 1개의 탑레벨 클래스를 담는다.
탑레벨 클래스(Top level class)는 소스 파일에 1개만 존재해야 한다.
- 나쁜 예
public class LogParser {
}
class LogType {
}
- 좋은 예
public class LogParser {
// 굳이 한 파일안에 선언해야 한다면 내부 클래스로 선언한다.
class LogType {
}
}
static import문에만 와일드 카드를 허용한다.
클래스를 import할때는 와일드카드(*) 없이 모든 클래스명을 다 쓴다.
static import에서는 와일드카드를 허용한다.
또한, static import와 import 그룹핑을 해서 아래 순서에 맞춰 작성한다. 다른 그룹간에는 공백라인을 한 줄 추가.
- static import
- import
import static baseball.Computer.*;
import static baseball.Message.*;
import java.util.ArrayList;
import java.util.HashSet;
제한자의 선언 순서
클래스/메서드/멤버변수의 제한자는 Java Language Specification에서 명시한 아래의 순서로 쓴다.
public
protected
private
abstract
static
final
transient
volatile
synchronized
native
strictfp
메서드는 접근자 기준으로 작성하지 않고 기능 및 역할별로 분류한다.
접근자 기준으로 작성하지 않고, 기능 및 역할별로 분류하여 기능을 구현하는 그룹별로 작성이 이루어지도록 해야한다.
기능 및 역할별로 분류되어 public 사이에 private 메소드가 존재할 수 있다
클래스는 상수, 멤버 변수, 생성자, 메서드 순으로 작성한다.
class A {
상수(static final) 또는 클래스 변수
인스턴스 변수
생성자
메서드
}
한 줄에 여러 문장을 쓰지 않고, 하나의 선언문에는 하나의 변수만을 다룬다.
문장이 끝나는 ; 뒤에는 새줄을 삽입한다.
변수 선언문은 한 문장에서 하나의 변수만을 다룬다.
- 나쁜 예
int base, weight;
- 좋은 예
int base;
int weight;
- 나쁜 예
int base = 0; int weight = 2;
- 좋은 예
int base = 0;
int weight = 2;
들여쓰기
- 4개의 빈 칸(space)를 들여쓰기 단위로 사용한다.
1개의 탭의 크기는 스페이스 4개와 같도록 에디터에서 설정한다.
File - Settings - Editor - Code Style - HTML
- 클래스, 메서드, 제어문 등의 코드 블럭이 생길 때마다 1단계를 더 들여쓴다.
중괄호
중괄호({,}) 는 클래스, 메서드, 제어문의 블럭을 구분한다.
중괄호 선언은 K&R 스타일(Kernighan and Ritchie style)을 따른다.
줄의 마지막에서 시작 중괄호`{`를 쓰고 열고 새줄을 삽입한다. 블럭을 마친후에는 새줄 삽입 후 중괄호를 닫는다.
public class SearchConditionParser {
public boolean isValidExpression(String exp) {
if (exp == null) {
return false;
}
return true;
}
}
닫는 중괄호와 같은 줄에 else, catch, finally, while을 선언한다.
- if문
if (line.startWith(WARNING_PREFIX)) {
return LogPattern.WARN;
} else if (line.startWith(DANGER_PREFIX)) {
return LogPattern.NORMAL;
} else {
return LogPattern.NORMAL;
}
- try catch문
try {
writeLog();
} catch (IOException ioe) {
reportFailure(ioe);
} finally {
writeFooter();
}
- while문
do {
write(line);
line = readLine();
} while (line != null);
조건/반복문에 중괄호를 필수로 사용한다.
조건, 반복문이 한 줄로 끝더라도 중괄호를 활용한다.
- 나쁜 예
if (exp == null) return false;
for (char ch : exp.toCharArray()) if (ch == 0) return false;
- 좋은 예
if (exp == null) {
return false;
}
for (char ch : exp.toCharArray()) {
if (ch == 0) {
return false;
}
}
줄바꿈
줄바꿈은 작성한 명령어가 줄 너비를 초과했을 경우 코드 가독성을 위해서 강제로 줄을 바꾸는 것을 말한다.
최대 줄 사용 너비는 120자까지 가능하다.
package,import 선언문 중간에서는 줄을 바꾸지 않는다. 최대 줄수를 초과하더라도 한 줄로 쓴다.
줄바꿈 후 추가 들여쓰기
줄바꿈 이후 이어지는 줄에서는 최초 시작한 줄에서보다 적어도 1단계의 들여쓰기를 더 추가한다.
IDE의 자동정렬 기능 ( 인텔리제이의 경우 ctrl + alt + l )을 활용한다.
AbstractAggregateRootTest.AggregateRoot proxyAggregateRoot =
em.getReference(AbstractAggregateRootTest.AggregateRoot.class, aggregateRoot.getId());
줄바꿈 허용 위치
가독성을 위해 줄을 바꾸는 위치는 다음 중의 하나로 한다.
extends 선언 후 | |
implements 선언 후 | |
throws 선언 후 | |
시작 소괄호(() 선언 후 | |
콤마(,) 후 | |
. 전 | |
연산자 전 |
|
public boolen isAbnormalAccess (
User user, AccessLog log) {
String message = user.getId() + "|" | log.getPrefix()
+ "|" + SUFFIX;
}
빈 줄
빈 줄은 명령문 그룹의 영역을 표시하기 위하여 사용한다.
package 선언 후 빈 줄을 삽입한다.
package baseball;
import java.util.List;
import 선언의 순서와 빈 줄 삽입
import 구절은 아래와 같은 순서로 그룹을 묶어서 선언한다.
static imports
java.
javax.
org.
net.
8~10을 제외한 com.*
1~6, 8~10을 제외한 패키지에 있는 클래스
com.nhncorp.
com.navercorp.
com.naver.
각 그룹 사이에는 빈줄을 삽입한다.
같은 그룹 내에서는 알파벳 순으로 정렬한다.
import java.util.Date;
import java.util.List;
import javax.naming.NamingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import com.google.common.base.Function;
import com.naver.lucy.util.AnnotationUtils;
메서드의 선언이 끝난 후 다음 메서드 선언이 시작되기 전에 빈줄을 삽입한다.
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
공백
빈줄을 포함하여 모든 줄은 탭이나 공백으로 끝내지 않는다.
대괄호 뒤에 공백 삽입
닫는 대괄호(]) 뒤에 `;`으로 문장이 끝나지 않고 다른 선언이 올 경우 공백을 삽입한다.
- 나쁜 예
int[]masks = new int[]{0, 1, 1};
- 좋은 예
int[] masks = new int[] {0, 1, 1};
중괄호 시작 전과 종료 후에 공백 삽입
여는 중괄호({) 앞에는 공백을 삽입한다.
닫는 중괄호(}) 뒤에 else ,catch 등의 키워드가 있을 경우 중괄호와 키워드 사이에 공백을 삽입한다.
public void printWarnMessage(String line) {
if (line.startsWith(WARN_PREFIX)) {
...
} else {
...
}
}
제어문 키워드와 여는 소괄호 사이에 공백 삽입
if, for, while, catch, synchronized, switch와 같은 제어문 키워드의 뒤에 소괄호((,)`)를 선언하는 경우, 시작 소괄호 앞에 공백을 삽입한다.
if (maxLine > LIMITED) {
return false;
}
식별자와 여는 소괄호 사이에는 공백을 삽입하지 않는다.
식별자와 여는 소괄호(() 사이에는 공백을 삽입하지 않는다.
생성자와 메서드의 선언, 호출, 애너테이션 선언 뒤에 쓰이는 소괄호가 그에 해당한다.
public StringProcessor() {} // 생성자
@Cached("local")
public String removeEndingDot(String original) {
assertNotNull(original);
...
}
타입 캐스팅(casting)에 쓰이는 소괄호 내부에 공백을 삽입하지 않는다.
- 나쁜 예
String message = ( String ) rawLine;
- 좋은 예
String message = (String)rawLine;
콤마/구분자 세미콜론의 뒤에 공백을 삽입한다.
콤마(,)와 반복문(while, for)의 구분자로 쓰이는 세미콜론(;)에는 뒤에만 공백을 삽입한다.
- 나쁜 예
for (int i = 0;i < length;i++) {
display(level,message,i)
}
- 좋은 예
for (int i = 0; i < length; i++) {
display(level, message, i)
}
주석문 기호 전후의 공백 삽입
주석의 전후에는 아래와 같이 공백을 삽입한다
- 명령문과 같은 줄에 주석을 붙일 때 // 앞
- 주석 시작 기호 // 뒤
- 주석 시작 기호 /* 뒤
- 블록 주석을 한 줄로 작성시 종료 기호 */ 앞
/*
* 공백 후 주석내용 시작
*/
System.out.print(true); // 주석 기호 앞 뒤로 공백
/* 주석내용 앞에 공백, 뒤에도 공백 */
'◼ CS 기초 지식 > [개발상식]' 카테고리의 다른 글
프레임워크? 라이브러리? 쉽게 이해하기 (0) | 2023.04.24 |
---|---|
힙(Heap) 자료구조 (0) | 2023.01.21 |
MVC 디자인 패턴이란? (0) | 2022.11.08 |
[Java/자바] 인터페이스(interface)란 ? (0) | 2022.10.25 |
객체지향프로그래밍 (OOP)에 대해 알아보자. (0) | 2022.10.22 |