3주간의 우아한테크코스 4기 프리코스 과정이 끝났습니다.
프리코스를 진행하며 학습한 내용들을 정리하고,
혹은 놓쳤던 부분에 대해 추가로 공부하여 보완한 내용들을 포스팅해보고자 합니다.
협업과 배려
3주간의 프리코스를 수행하며 가장 먼저 익히게 되는 부분은 코딩 컨벤션이었습니다.
2021 우아콘을 보며 배민에서 강조되는 가치 중 "배려"를 느낄 수 있었는데요,
코딩 컨벤션을 잘 지키는 것 역시, 함께 일하는 분들을 위한 배려일 수 있겠다는 생각을 해봅니다.
코딩 컨벤션의 기준
우아한테크코스 소개 영상을 보며, 또 박재성님의 여러 발표 등을 보며
스스로 성장할 수 있는 힘을 길러주시는 점이 정말 멋지다고 생각해왔습니다.
그렇다고 이것이 방치를 의미하지는 않습니다.
학습과 성장에 필요한 소스들을 시의적절하게 제공해주시는데요,
프리코스를 진행하는 과정에서 지켜야할 코딩 컨벤션을 학습할 수 있는 소스와 기준을 제공해주셨습니다.
그것은 바로 네이버 캠퍼스 핵데이 에서 제공된 코딩 컨벤션 문서였습니다.
이 포스팅에서는 해당 링크의 모든 내용을 다시 다루지는 않고,
평소 제 습관과 달랐거나 몰랐던 부분만 정리해보고자 합니다.
목차
1. 새줄 문자는 LF
2. 대문자로 표시할 약어 명시
3. static import 만 와일드 카드 허용
4. 제한자 선언 순서
5. 닫는 중괄호와 같은 줄에 else, catch, finally, while 선언
6. 빈 블럭에 새줄 없이 중괄호 닫기 허용
7. .editorconfig 파일 설정
8. Checkstyle 플러그인, IntelliJ, Gradle 연동
9. Save Actions 플러그인으로 프로젝트 전체 Reformatting
10. Checkstyle Suppressions 예외 설정
1. 새줄 문자는 LF
Unix 형식의 새줄 문자(newline)인 LF(Line Feed, 0x0A)을 사용한다.
Windows 형식인 CRLF가 섞이지 않도록 편집기와 GIT 설정 등을 확인한다.
줄 바꿈 문자에 대한 이야기인 건 이해했지만, LF, CRLF가 무엇인지 처음엔 알지 못했습니다.
검색중에 MDN 공식문서에서 CR LF에 대한 설명을 찾을 수 있었습니다.
CR은 Carriage Return의 약자로, 커서를 현재 줄에서 가장 왼쪽으로 보냄을 뜻합니다.
LF는 Line Feed의 약자로, 줄 바꿈을 의미합니다.
예전 타자기로 문서에 글을 작성할 때,
줄바꿈을 위해서 Line을 Feed 시킨 뒤에 Carriage의 위치를 Return시키는 것을 떠올리면 쉽습니다.
즉, LF는 커서의 위치이동은 제외하고, 줄만 바꾸는 문자이고,
CRLF는 커서의 위치이동과 줄바꿈이 합쳐진 문자입니다.
Windows 는 CRLF, Unix-Like OS 는 LF
Windows에서는 CRLF를 Unix 계열에서는 LF를 기본 개행문자로 사용한다고 합니다.
그래서 직접 CRLF와 LF가 어떤 차이가 있는지 눈으로 정확히 확인하고 싶었습니다.
감사하게도 VS Code에서는 화면 하단 표시줄에 현재 적용되는 개행문자가 CRLF인지 LF인지 표기해주고,
두 번의 클릭으로 해당 옵션을 변경할 수 있었습니다.
CRLF와 LF로 개행을 한 텍스트 파일을 두 개 생성했습니다.
그리고 이를 직접 확인해보고자 메모장에서 열었습니다.
구글링해서 찾아본 일부 블로그에선 LF형식의 파일을 메모장에서 열었을 때,
개행 문자가 이상하게 표시되는 경우가 있었는데,
Windows 10 최신 버전을 사용하고 있는 현재 시점에서는 두 형식 모두 잘 호환되는 것 같았습니다.
덕분에(?) CRLF와 LF의 차이를 눈으로 확인할 순 없었습니다.
그래서...
WSL 설치 및 CRLF, LF 차이 확인
wsl --install
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
관리자 권한으로 연 Power Shell에서 위 두 명령어를 수행한 뒤,
BIOS에서 Advanced -> OC -> Advanced Configurations -> SVM Mode -> Enabled 옵션을 설정했습니다.
(AMD, MSI 보드 기준)
니콜라스 유튜브를 통해 WSL에 대해 이야기는 들었지만 직접 설치한 것은 처음이었습니다.
그리고, 윈도우 파일 탐색기에서 \\WSL$ 명령어를 이용해 ubuntu 설치 경로로 이동한 뒤,
앞서 생성한 두 텍스트파일을 이동했습니다.
그리고 드디어 cat 명령어로 개행문자를 눈으로 확인할 수 있었습니다.
CRLF는 ^M$로 표기되었고, LF는 $로 표기되었습니다.
즉, ^M은 CR에 해당하고 LF는 $에 해당한다는 것을 알 수 있었습니다.
버전 관리와 새줄 문자 통일의 필요성
git 공식 문서를 확인해보면 빠른 이해가 가능할 것 같습니다.
요약하자면, 앞서 살펴봤듯, OS에 따라 새줄 문자가 바뀔 경우,
실제 수정 내역이 없는 파일에 대해서도 파일이 수정된 것으로 인식될 가능성이 있기 때문에,
이에 대해 협업을 위한 설정을 해야하는 것입니다.
IntelliJ에서 프로젝트를 신규로 생성한 뒤 새줄 문자를 확인해봤습니다.
설정상으로도 LF로 표기되고, cat 명령어로 확인했을 때도 정상적으로 LF로 확인됩니다.
그러나, 원격 저장소에 있는 프로젝트를 git clone 한 뒤 열었을 경우에는 달랐습니다.
CRLF로 열려있습니다. 확인해봐도 CRLF입니다.
Windows 에서의 새줄 문자 설정
윈도우에서의 대응은 크게 두 가지로 나뉩니다.
첫번째는 git 전역설정, 두번째는 프로젝트 내 gitattribute파일 설정입니다.
먼저 첫번째 방법입니다.
Git은 커밋할 때 자동으로 CRLF를 LF로 변환해주고
반대로 Checkout 할 때 LF를 CRLF로 변환해 주는 기능이 있다.
core.autocrlf 설정으로 이 기능을 켤 수 있다.
Windows에서 이 값을 true로 설정하면 Checkout 할 때 LF 문자가 CRLF 문자로 변환된다
git bash에서 전역설정을 하는 모습입니다.
첫 두 줄은 eol설정과 autocrlf 설정이 없음을 나타내고,
세번째줄은 autocrlf 설정을 true로 설정하는 모습이고,
네번째줄은 autocrlf 설정이 true로 설정된 것을 확인하는 모습입니다.
Windows에서는 이 값을 true로 설정하여 사용하면,
커밋 시 CRLF가 LF로 자동 변환되기 때문에, 원격 저장소에는 LF로 push될 것입니다.
두번째 방법은 .gitattribute 설정입니다.
*.java text eol=lf
*.md text eol=lf
*.gitattribute text eol=lf
위와 같은 내용을 담은 .gitattribute 파일을 생성한 뒤, 프로젝트 최상단에 위치시키는 것입니다.
* text=auto eol=lf 와 같은, 깃의 텍스트파일 자동 탐지 기능을 이용해 전체에 LF설정을 줄 수도 있지만,
binary file에 대한 탐지가 완전하지 않기 때문에 저는 사용하지 않기로 했습니다.
새줄 문자는 LF 요약
- Windows 는 CRLF를, Unix 계열은 LF를 새줄 문자 기본값으로 사용합니다.
- 플랫폼간 원활한 협업을 위해 LF를 기본값으로 통일시켜야 합니다.
- Windows에서는 git config --global core.autocrlf true 설정을 하여 원격 저장소에 LF로 올리도록 설정합니다.
- 레포지토리 최상단에 .gitattribute 파일을 이용해 별도 설정 없이 플랫폼간 더욱 편하게 협업할 수 있습니다.
2. 대문자로 표시할 약어 명시
약어의 경우, 보통 전체 대문자를 사용하여 표기합니다.
가령 JSON, HTTP, XML 등과 같이 말입니다.
그러나 그러한 약어가 합쳐질 경우, 가독성을 해칠 우려가 있습니다.
가령 HTTPJSONXML 은 정말 읽기 어렵죠.
그래서 프로젝트 단위마다 대문자로 표기할 약어를 미리 약속을 정해야 합니다.
만약 해당 프로젝트에서 JSON 만큼은 반드시 전체 대문자료 표기하기로 약속했다면,
해당 프로젝트에서는 HttpJSONXml와 같이 작성해야겠습니다.
만약 모든 단어가 대문자 표기 대상이라면 HTTPJSONXML로 작성하는 것이 맞고,
아무 단어도 대문자 표기 대상이 아니라면 HttpJsonXml로 표기하면 됩니다.
이런 경우는 아직까지는 업무중에 만나보지 못했는데,
나중에 이런 경우를 만났을 때 조금 더 컨벤션 준수가 수월할 것 같습니다.
3. 기타 규약
간단히 요약할 수 있는 규약을 모았습니다.
1) static import 만 와일드 카드 허용
즉, static이 아닌 import의 경우, 갯수가 많아지더라도 와일드 카드를 사용하지 않아야 합니다.
2) 제한자 선언 순서
public protected private abstract static final transient volatile synchronized native strictfp
사실 처음 보는 제한자도 있습니다 ^^;
여러 메소드가 하나의 클래스에 속할 때, public과 private이 뒤섞이는 경우가 있었는데,
이 규약을 알게되어 기존 습관을 바로잡는 계기가 되었습니다.
3) 닫는 중괄호와 같은 줄에 else, catch, finally, while 선언
가독성을 높인다는 목적으로 else, catch 등을 if, try의 닫는 중괄호와 다른 줄에 작성하곤 했는데
같은 줄에 작성하는 것으로 기존 습관을 바로잡았습니다.
4) 빈 블럭에 새줄 없이 중괄호 닫기 허용
public void close() {}
4. .editorconfig 파일 설정
editorconfig는 여러 개발자가 하나의 프로젝트에서 작업할 때,
동일한 코드 스타일을 유지할 수 있게 도와줍니다.
자세한 스펙은 공식 홈페이지에서 확인 가능합니다.
이하는 예제 파일입니다.
이 파일을 프로젝트 최상단에 .editorconfig 라는 이름으로 저장하면 됩니다.
인텔리제이는 별도 플러그인 설치가 필요없고, 이클립스는 플러그인 설치가 추가로 요구됩니다.
이 파일도 저장소에 올려서 공유할 것이 권장되고 있습니다.
설정을 살펴보면, utf-8 인코딩, 새줄 문자 LF, 파일 끝에 LF 추가, 들여쓰기 탭을 스페이스4개 등이 확인됩니다.
인텔리제이에서 .editorconfig 파일을 프로젝트 루트 경로에 넣어둔 뒤,
파일 맨 끝의 새 줄을 제거하고 저장을 하자, 새줄이 자동으로 추가되는 것을 확인했습니다.
# top-most EditorConfig file
root = true
[*]
# [encoding-utf8]
charset = utf-8
# [newline-lf]
end_of_line = lf
# [newline-eof]
insert_final_newline = true
[*.bat]
end_of_line = crlf
[*.java]
# [indentation-tab]
indent_style = tab
# [4-spaces-tab]
indent_size = 4
tab_width = 4
# [no-trailing-spaces]
trim_trailing_whitespace = true
[line-length-120]
max_line_length = 120
5. Checkstyle 인텔리제이에 적용
Checkstyle은 코딩 컨벤션을 검사하는 도구입니다.
Maven이나 Gradle 등의 빌드 도구와 연계해서, 컨벤션을 위배한 파일이 있으면
빌드를 실패하게 할 수 있습니다.
또한 IDE와 연동해서 간편하게 XML파일을 주입하는 것만으로 사용하는 방법도 있습니다.
Checkstyle로 모든 내용을 검사할 수는 없지만,
이번 포스팅에선 인텔리제이에 XML 설정 파일을 주입하는 방법과,
컨벤션을 어긴 파일에 대해 빌드 시 실패가 되도록 설정하는 방법을 알아보겠습니다.
1) build.gradle
editorconfig, checkstyle에 대한 설정을 추가해줍니다.
checkstyle 스코프를 보시면 프로젝트 루트 경로에 파일 두 개를 추가해야할 것을 알 수 있습니다.
plugins {
id 'org.ec4j.editorconfig' version '0.0.3'
id 'checkstyle'
id 'java'
}
editorconfig {
excludes = ['build']
}
checkstyle {
maxWarnings = 0
configFile = file("${rootDir}/naver-checkstyle-rules.xml")
configProperties = ["suppressionFile" : "${rootDir}/naver-checkstyle-suppressions.xml"]
toolVersion = "9.2"
}
check.dependsOn editorconfigCheck
compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'
2) 규칙 파일 추가
네이버 핵데이 레포지토리에서 규칙 파일 두 개를 내려받아 프로젝트 루트 경로에 추가합니다.
naver-checkstyle-rules.xml 파일과, naver-checkstyle-suppressions.xml 파일 두 개입니다.
3) 플러그인 설치
인텔리제이 플러그인을 설치합니다. CheckStyle-IDEA 입니다.
4) Checkstyle 설정
Settings > Tools > Checkstyle 메뉴에 진입합니다.
버전은 최신버전을 그대로 사용했고, Scan Scope는 테스트를 포함한 전체로 선택했습니다.
체크스타일 에러를 warnings로 취급하도록 체크해줍니다.
그리고 바로 아래 Confiruation File 밑에 있는 + 버튼을 눌러 규칙파일 추가를 시작합니다.
루트 경로에 추가해줬던 두 개의 파일 중, naver-checkstyle-rules.xml 파일을 선택하고 Next를 누릅니다.
다음 창에서 파일 경로를 지정해줘야하는 프로퍼티가 나타납니다.
해당 프로퍼티는 naver-checkstyle-rules.xml 에 변수처리되어 있는데,
Value를 지정해주지 않으면 parse 오류가 나왔습니다.
받아 두었던 두 파일 중 suppressions 파일 이름을 작성해줍니다.
둘 다 같은 경로에 있으므로 파일명만 작성해도 됩니다.
최종 설정 완료 모습입니다.
5) CheckStyle Scan
설정 완료 후, 하단에서 CheckStyle 탭을
확인할 수 있습니다.
단일 파일, 단일 모듈, 프로젝트 전체 범위로 스캔을 할 수 있습니다.
탭 상단에서 먼저 생성해둔 규칙을 선택하고, 스캔을 하면,
규칙을 어긴 파일과 파일 내 규칙을 어긴 위치 및 규칙 내용이 상세하게 나타납니다.
CRLF가 굉장히 많이 탐지되었네요.
Answer.java의 파일 중간 새줄 문자와 파일 마지막 새줄 문자가 모두 CRLF로 되어있다는 모습입니다.
6. Checkstyle Unable to create Root Module
인텔리제이 내 플러그인으로는 스캔 기능이 정상 작동하는 걸 확인했으니,
코딩 컨벤션 위반사항이 발견되면 빌드를 실패하게 만드는 gradle 플러그인 연동을 확인해보고 싶었습니다.
그런데 컨벤션 위반으로 인한 빌드 실패가 아니라,
checkstyleMain을 실행하는 중에 Root Module 생성에 실패했음을 확인했습니다.
버전도 바꿔보고 일부 모듈을 제외해보는 등 여러 시도를 해봤으나 결국 해결되지 않았는데,
오류 내용을 자세히 읽어보니... naver-chestyle-rules.xml 이라는 파일명이 눈에 들어왔습니다.
네이버 핵데이에 있는 gradle 설정 내용을 그대로 복사해왔었는데,
그때 파일명에 오타가 있음을 확인했습니다. 으읔.. ㅠㅠ
해당 링크를 통해 체크스타일을 적용하시는 분들은 아마 한 번쯤 다 겪고 가는 문제가 아니었을까 싶네요... ;ㅅ;
그래서 오타를 수정하고 다시 실행해본 결과!
인텔리제이 플러그인 탭에서 확인했던 것과 동일한 내용을 확인할 수 있었습니다.
물론 빌드도 실패했습니다.
하지만 정상적으로 코딩 컨벤션 규약이 작동하고 있음을 확인했습니다.
이제 위반 내역을 수정해봅시다!
7. IntelliJ Formatter 적용
네이버 핵데이 레포지토리에서 naver-intellij-formatter.xml 파일을 다운받습니다.
Code Style > Java 에 접근한 뒤, 톱니바퀴를 눌러 다운받은 파일을 선택합니다.
이후부터는 Ctrl Alt L 을 이용해 인텔리제이의 자동 정렬 기능을 사용할 때,
naver-intellij-formatter.xml 의 설정에 따라 정렬될 것입니다.
8. Save Actions로 한 방에 컨벤션 검사 모두 탈출하기
1) Save Actions 플러그인을 설치하고 인텔리제이를 재시작합니다.
2) Save Actions 옵션을 선택합니다. 체크박스 3개를 체크해줍니다.
3) 프로젝트 일괄 적용
프로젝트 루트 디렉토리 우클릭 후 Reformat Code 선택
Optimize imports 체크 후 Run
4) 결과 확인
테스트 메소드 이름이 한글이어서 규약 위반이라고 나타난 부분을 제외한 모든 컨벤션 위반이 사라졌습니다.
5) 예외 처리
naver-checkstyle-suppressions.xml 파일에 아래 내용을 기입합니다.
해당 클래스에서는 MethodName 검사를 하지 않겠다는 설정입니다.
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files="ApplicationTest.java" checks="MethodName"/>
</suppressions>
9. 모든 컨벤션 준수 완료
1) .editorconfig 적용
2) checkstyle 에 naver-intellij-formatter.xml 적용
3) save actions 를 이용해 전체 프로젝트에 리포맷팅 및 세이브 액션 활성화
4) gradle 설정을 통해 빌드 시 컨벤션 위반 발생 시 빌드 실패 적용
5) checkstyle, editorconfig 의 모든 컨벤션 통과 및 빌드 성공 완료
드디어 모든 컨벤션에 대한 요구사항이 충족되었습니다.
10. 소감
처음 구축하기까지는 다소 어려움을 겪을 수 있지만,
컨벤션 준수는 협업에 있어서 필수적인 요소라고 생각합니다.
단순히 패키지 이름이나 클래스 이름 및 경로 지정 방법 등에 대해서만 생각해왔는데,
이렇게 체계적으로 컨벤션 준수를 자동화할 수 있다는 게 놀라웠고 많이 배웠습니다.
이번에 구축한 내용을 앞으로 개인 프로젝트에도 기본값으로 가져갈 계획입니다.
감사합니다.
출처
https://naver.github.io/hackday-conventions-java
https://github.com/naver/hackday-conventions-java
'우아한테크코스 4기' 카테고리의 다른 글
우아한테크코스 웹 백엔드 4기, 화음을 좋아하는 리차드 (0) | 2022.01.20 |
---|---|
우아한테크코스 4기 프리코스 후기 (4) - README.md 작성 (markdown) (0) | 2021.12.17 |
우아한테크코스 4기 프리코스 후기 (3) - Github, Git, 과제제출방법 (0) | 2021.12.17 |
우아한테크코스 4기 프리코스 후기 (2) - Commit Log 컨벤션 (7) | 2021.12.16 |
우아한 테크캠프 Pro ! 선 지원 후 고민! (0) | 2021.09.14 |