컨벤션 심화 - Google Java Style Guide

StrayCat·2026년 3월 8일

CS지식

목록 보기
15/32

Google Java Style Guide — 왜 존재하고, 무엇을 담고 있는가

참고 링크: Google Java Style Guide 공식 문서


Java를 어느 정도 다뤄본 사람이라면 한 번쯤 이런 상황을 겪어봤을 것이다.

PR(Pull Request)을 올렸더니 리뷰어가 코드 내용이 아닌 스타일을 지적한다. 들여쓰기가 다르다, 중괄호 위치가 다르다, 변수명 규칙이 맞지 않는다. 팀원마다 코드 스타일이 제각각이라 merge(병합)할 때마다 diff(변경 사항 비교)가 엉망이 된다.

이런 문제를 근본적으로 정리하기 위해 만들어진 것이 바로 코딩 컨벤션(Coding Convention) 이다. 그리고 그 중에서도 Java 생태계에서 널리 사용되는 것이 Google Java Style Guide다. 특히 Google 계열 프로젝트나 많은 오픈소스 프로젝트에서 사실상 표준처럼 사용된다.


1. 이 문서의 목적

Google Java Style Guide는 Google이 내부적으로 Java 소스 코드에 적용하는 코딩 표준의 완전한 정의다.

"A Java source file is described as being in Google Style if and only if it adheres to the rules herein."

(이 문서에 정의된 규칙을 따를 때, 그 소스 파일을 'Google Style'이라고 부를 수 있다.)

핵심은 이 가이드가 '주관적인 조언'이 아니라 '강제 가능한 규칙' 에만 집중한다는 점이다. 취향의 영역은 가능한 배제하고, 팀 전체가 지킬 수 있는 명확하고 구체적인 규칙만 담는 것이 이 문서의 철학이다.

무엇을 다루는가:

  • 소스 파일 구조 (파일 이름, 인코딩, 공백 처리)
  • 포매팅 규칙 (중괄호, 들여쓰기, 줄 길이, 공백 처리)
  • 네이밍 컨벤션 (패키지, 클래스, 메서드, 변수, 상수)
  • 프로그래밍 관례 (@Override, 예외 처리, static 멤버 참조)
  • Javadoc 규칙

2. 소스 파일 기본 규칙

파일명과 인코딩

  • 파일명은 최상위 클래스명과 정확히 동일 해야 한다. 대소문자도 구분한다.
  • 모든 소스 파일의 인코딩은 UTF-8이다.
// 파일명: UserService.java
public class UserService {
    // ...
}

공백 문자

  • 줄 끝의 공백은 허용하지 않는다.
  • 탭(tab)은 사용하지 않는다. 들여쓰기는 오직 스페이스 로만 한다.

이 규칙이 꽤 엄격하게 느껴질 수 있는데, 탭과 스페이스가 혼용되면 IDE나 뷰어마다 표시가 달라지기 때문이다. 일관성을 위해 스페이스로 통일한다.


3. 소스 파일 구조 (Source File Structure)

파일 내 구성 요소는 아래 순서 대로 작성해야 한다.

  1. 라이선스 또는 저작권 정보 (있다면)
  2. package
  3. import
  4. top-level 클래스 선언 (일반적으로 하나만) (또는 인터페이스, enum 등)

import 규칙

와일드카드 import는 금지 한다. 이 규칙은 처음엔 불편하게 느껴지지만, 어떤 클래스가 어디서 왔는지 명확하게 보이기 때문에 코드 가독성에 실질적으로 도움이 된다.

// Bad - 와일드카드 import
import java.util.*;

// Good - 명시적 import
import java.util.List;
import java.util.Map;
import java.util.Optional;

import 순서는 다음과 같다:

  1. static import (알파벳 순)
  2. 일반 import (알파벳 순)

그룹 사이에 빈 줄 하나를 둔다. Google Style에서는 static import와 일반 import를 명확히 분리 한다.

일부 IDE에서는 일정 개수 이상의 import가 있으면 자동으로 *로 합치는 기능이 있는데, Google Style에서는 이를 사용하지 않는다.


4. 포매팅 규칙 (Formatting)

중괄호 (Braces)

Google Style은 K&R 스타일 (Egyptian Brackets) 을 따른다.

// Google Style - 여는 중괄호는 같은 줄에
if (condition) {
    doSomething();
} else {
    doOtherThing();
}

// 내용이 한 줄이더라도 중괄호 생략 금지
// Bad
if (condition)
    doSomething();

// Good
if (condition) {
    doSomething();
}

단 한 줄짜리 블록이라도 반드시 중괄호를 붙인다. 이 규칙이 중요한 이유는, 중괄호를 생략했다가 나중에 줄을 추가할 때 버그가 발생하는 사례가 실제 개발 환경에서 꽤 자주 생기기 때문이다.

들여쓰기

  • 들여쓰기 단위: 2 스페이스
  • 줄 연속 시 (line-wrapping): 최소 +4 스페이스

참고로 Oracle의 공식 Java 스타일은 4 스페이스를 권장한다. Google Style은 2 스페이스를 쓰는데, 이 점은 팀이나 프로젝트에 따라 충분히 논의가 필요한 부분이다.

줄 길이 (Column Limit)

한 줄은 100자 를 넘지 않는다. 넘어가면 줄 바꿈(line-wrapping)을 해야 한다.

줄 바꿈의 기본 원칙은 높은 문법 수준에서 먼저 나누는 것 이다. 예를 들어 메서드 체이닝이 길어질 경우 아래처럼 정리한다.

// 줄이 너무 길 때 - 연산자 앞에서 줄 바꿈
String result = someObject
    .methodA()
    .methodB()
    .methodC();

// 파라미터가 많을 때
public void someMethod(
    String paramA,
    String paramB,
    int paramC) {
    // ...
}

공백 규칙

// 키워드와 괄호 사이에 공백
if (condition) { ... }
for (int i = 0; i < n; i++) { ... }

// 이항/삼항 연산자 양쪽에 공백
int result = a + b;
int max = (a > b) ? a : b;

// 콤마, 세미콜론 뒤에 공백
method(a, b, c);

실제 팀에서는 스타일 가이드를 "문서로 외우는 것"보다 formatter로 강제하는 것이 훨씬 중요하다.


5. 네이밍 컨벤션 (Naming Conventions)

이 부분은 Java를 쓰는 사람이라면 대부분 익숙하지만, Google Style이 명확하게 정의하고 있어서 한 번 정리해두는 것이 좋다.

대상규칙예시
패키지소문자 + 연속된 단어 그냥 붙이기com.example.deepspace
클래스 / 인터페이스UpperCamelCase (명사 또는 명사구)UserService, ImmutableList
메서드lowerCamelCase (동사 또는 동사구)sendMessage(), getUserById()
변수lowerCamelCaseuserCount, firstName
상수CONSTANT_CASE (대문자 + 언더스코어)MAX_RETRY_COUNT
타입 파라미터단일 대문자 또는 대문자+숫자T, E, K, V, T2
테스트 메서드lowerCamelCase + 언더스코어 허용getUserById_notFound()

상수(Constant)의 정의 에 주목할 필요가 있다. Google Style에서 상수는 단순히 static final 필드가 아니라, 관찰 가능한 상태가 변경되지 않는 필드를 말한다. 즉, 단순히 변경할 의도가 없다고 상수처럼 취급할 수 없다.

// 진짜 상수 - 불변이고 상태 변화 없음
static final int MAX_SIZE = 100;
static final ImmutableList<String> NAMES = ImmutableList.of("Alice", "Bob");

// 상수가 아님 - 내부 상태가 변할 수 있는 객체
static final List<String> MUTABLE_LIST = new ArrayList<>(); // CONSTANT_CASE 사용 금지

6. 프로그래밍 관례 (Programming Practices)

@Override — 항상 붙여라

합법적으로 사용 가능한 모든 경우에 @Override를 붙이는 것이 원칙이다. 부모 클래스나 인터페이스의 메서드를 재정의할 때 이 어노테이션이 없으면, 시그니처를 잘못 작성해도 컴파일러가 잡아주지 못한다.

// Bad
public String toString() {
    return "User{id=" + id + "}";
}

// Good - @Override로 컴파일 시점에 검증
@Override
public String toString() {
    return "User{id=" + id + "}";
}

예외(Exception) — 절대 무시하지 마라

catch 블록을 비워두는 것은 매우 위험하다. 정말로 무시해야 하는 경우에는 그 이유를 주석으로 남겨야 한다.

// Bad - 예외를 조용히 삼킴
try {
    doSomething();
} catch (Exception e) {
    // 아무것도 안 함
}

// Good - 무시할 경우 이유 명시
try {
    doSomething();
} catch (SomeExpectedException expected) {
    // 이 예외는 정상적인 흐름의 일부다. 해당 케이스에서는 무시해도 안전하다.
}

Static 멤버 참조

static 멤버를 참조할 때는 클래스명 을 통해 접근해야 한다. 인스턴스나 표현식을 통한 참조는 혼란을 준다.

// Bad - 인스턴스를 통한 static 접근
Foo foo = new Foo();
foo.staticMethod(); // staticMethod가 static인지 한눈에 안 보임

// Good - 클래스명으로 접근
Foo.staticMethod();

7. Javadoc

어디에 작성해야 하는가

최소한 모든 public 클래스와 public / protected 멤버 에는 Javadoc을 작성해야 한다. 단, 아주 명백하고 단순한 메서드(예: getFoo())는 생략 가능하다.

하지만, 그 메서드가 "자명하지 않은 개념"을 다루고 있다면 반드시 작성해야 한다. getCanonicalName()처럼 독자가 'canonical name'이 무엇인지 모를 수 있는 경우에는 Javadoc이 필수다.

형식

/**
 * Returns an Image object that can then be painted on the screen.
 *
 * @param url an absolute URL giving the base location of the image
 * @param name the location of the image, relative to the url argument
 * @return the image at the specified URL
 * @throws MalformedURLException if url is not a valid URL
 */
public Image getImage(URL url, String name) throws MalformedURLException {
    // ...
}

짧고 자명한 경우 한 줄로 작성할 수도 있다.

/** Returns the user's full name. */
public String getFullName() {
    return fullName;
}

8. 실제 적용: google-java-format 도구

규칙을 외워서 손으로 지키는 것은 비효율적이다. Google은 이 스타일 가이드를 자동으로 적용해주는 google-java-format 이라는 포매터(formatter, 코드 형식 자동 정리 도구)를 제공한다.

이 도구의 가장 큰 특징은 설정이 존재하지 않는다는 것 이다. 의도적인 결정으로, 팀 내에서 포매팅 옵션에 대한 논쟁 자체를 없애버린다.

google-java-formatdeterministic formatter다. 즉, 동일한 코드는 언제 실행하더라도 항상 동일한 결과를 만든다. 이는 formatter에서 중요한 개념이다.

IDE 통합

IntelliJ IDEA / Android Studio

  1. Settings → Plugins → Marketplace에서 google-java-format 검색 후 설치
  2. Settings → google-java-format Settings에서 활성화
  3. 활성화 이후 기존 Reformat Code (Ctrl+Alt+L) 단축키가 자동으로 대체된다.
  4. 최신 JDK 환경에서는 Help → Edit Custom VM Options에 아래를 추가해야 한다.
--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED

Eclipse

Window → Preferences → Java → Code Style → Formatter → Formatter Implementation에서 설정 가능하다.

Maven 통합

<!-- pom.xml -->
<build>
    <plugins>
        <plugin>
            <groupId>com.spotify.fmt</groupId>
            <artifactId>fmt-maven-plugin</artifactId>
            <version>2.23</version>
            <executions>
                <execution>
                    <goals>
                        <!-- 검사만 할 때: check / 자동 수정할 때: format -->
                        <goal>check</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Gradle 통합

// build.gradle
plugins {
    id 'com.diffplug.spotless' version '6.25.0'
}

spotless {
    java {
        googleJavaFormat()
    }
}

CI/CD 파이프라인 (GitHub Actions 예시)

# .github/workflows/code-style.yml
name: Code Style Check

on: [pull_request]

jobs:
  format-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'
      - name: Check code formatting
        run: ./mvnw fmt:check  # 혹은 ./gradlew spotlessCheck

PR이 올라올 때마다 스타일을 자동으로 검증하게 만들면, 코드 리뷰 시간을 본질적인 로직 검토에 집중할 수 있다.


9. 현실적인 이야기

Google Style vs 일반 Java 관례

항상 짚고 넘어가야 하는 차이점이 있다.

항목Google StyleOracle 일반 관례
들여쓰기2 스페이스4 스페이스
줄 길이100자80자 권고
중괄호 생략금지허용 (주관에 따라)

2 스페이스 들여쓰기는 처음엔 낯설 수 있다. 기존에 4 스페이스에 익숙한 팀이라면 스타일 가이드 도입 시 별도 합의가 필요할 수 있다.

레거시 코드베이스에서의 도입

이미 수십만 줄의 코드가 기존 스타일로 작성된 프로젝트에 google-java-format을 전체 적용하면, 엄청난 양의 diff가 한 번에 발생 한다. 이 때문에 blame 기록이 무의미해질 수 있다. 또한 이는 코드 히스토리(blame, git log)를 오염시킬 수 있다.

이런 경우 권장되는 접근법은:

  • 모듈 단위 로 점진적으로 적용하거나,
  • 스타일 변경을 별도 커밋 하나로 분리 해서 기능 변경과 명확히 구분하는 것이다.

이미 구축된 레거시 환경에서 스타일 가이드를 도입할 때는 팀 전체의 합의와 단계적 접근이 필수다.


마무리

Google Java Style Guide를 처음 접하면 "이걸 다 외워야 해?" 싶은 생각이 든다. 하지만 외울 필요는 없다. google-java-format 도구를 IDE에 연동해두면 대부분의 포매팅 규칙은 자동으로 적용된다.

진짜 중요한 것은 왜 이런 규칙들이 존재하는가 를 이해하는 것이다. 코딩 스타일 가이드의 본질은 개인 취향 강요가 아니다. 팀이 같은 언어로 코드를 읽을 수 있게 하고, 코드 리뷰의 초점을 "중괄호가 왜 여기 있지?"가 아닌 "이 로직이 맞는가?"로 맞추기 위한 약속이다.

코드는 한 번 쓰고 수십 번 읽힌다. 그 읽는 시간을 아끼는 것이 스타일 가이드의 가장 솔직한 이유다.

profile
알면 좋은 것보단 잊어버리기 싫은 것들을 기록합니다.

0개의 댓글