⎮ 들어가며..
면접을 보던 중 Swift Lint에 대한 이야기를 들었습니다
"작성한 코드 중에 개행 문자가 일치가 잘 안되는 부분이 있네요? SwiftLint를 사용해보셔도 좋았을거 같아요"
면접관님께 "돌아가서 부족한 부분을 채우겠다"고 말씀드리기도 했고,
Swift Lint는 키워드로만 알고 있었어서 사용법과 함께 간단한 정리를 해보려고 합니다
⎮ Swift Lint란
Swift Lint는 Swift 코드 스타일과 관련된 정적 분석 도구입니다
조금 과장하자면, 일정한 규칙을 가진 작은 컴파일러를 하나 더 만든다고 생각하시면 됩니다
Swift Lint는 한국어 ReadMe도 있기 때문에, 다른 라이브러리에 비해 비교적 쉽게(?) 적용해볼 수 있습니다
https://github.com/realm/SwiftLint/blob/main/README_KR.md
SwiftLint/README_KR.md at main · realm/SwiftLint
A tool to enforce Swift style and conventions. Contribute to realm/SwiftLint development by creating an account on GitHub.
github.com
에러 없이 바로 적용하고 싶으신 분은, SPM으로 바로 넘어가주세요
⎮ Swift Lint가 왜 필요한데?
협업을 하다보면, 다양한 협업 규칙이 생겨납니다
1. Class를 선언할 때 내부 코드 작성 전 개행은 1개만 하자
2. 줄 길이는 120자를 넘기지 말자
3. 강제 언래핑은 사용하지 말자
4. 미사용하는 import는 정리하자
.
.
.
개인이 아닌 팀프로젝트를 기준으로 했을 때, '좋은 코드'란 무엇일까요?
팀의 컨벤션이 잘 지켜진 코드도 그 중 하나일 것 같습니다
Swift Lint는 바로 이 지점에서 필요합니다
PR을 할 때마다 일일히 "공백 줄 이상해요", "줄 길이가 너무 길어요", "인덴트 달라요" 하는 대신,
Tool로써 lint를 사용하고 규칙을 먼저 체크해주는 것도 개발자의 피로도를 낮춰줄 수 있습니다
⎮ Swift Lint 설치하기
Swift Lint는 brew 또는 CocoaPods으로 설치할 수 있습니다(저는 하기의 오류들로 인해 SPM 방식을 사용했습니다)
저는 brew를 기준으로 설치해보겠습니다
설치 방법은 간단합니다
brew install swiftlint
터미널에서 다음과 같은 명령어를 입력하면 됩니다
⎮ 프로젝트에 SwiftLint 적용하기
Project - TARGETS - BuildPhase에서 + 버튼을 누르고 New Run Script Phase를 선택합니다

그 후 Run Script 안에 하기의 내용을 추가하면 됩니다
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
이 내용을 추가하면 Navigator 영역(⌘ + 9)에서 다음과 같은 에러를 만날 수 있습니다

애플 실리콘 환경에서 lint를 설치했기 때문에, 경로를 읽어오지 못합니다
ReadMe에 있는 가이드에 따라서 스크립트를 다음과 같이 바꿔줍니다(빌드 에러가 발생합니다)
if [[ "$(uname -m)" == arm64 ]]; then
export PATH="/opt/homebrew/bin:$PATH"
fi
if which swiftlint > /dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
가이드대로 했는데, 빌드 에러가 납니다

로그에 나와 있는대로, Based on dependency analysis를 꺼줍니다

문제가 해결되지 않습니다

에러 로그를 보면,
SwiftLint가 검사 대상이 되는 Swift 파일을 못 찾은 것처럼 보입니다
User Script Sandboxing을 No로 설정하면 Build가 됩니다

왜 이런 오류가 발생했을까요?
User Script Sandboxing이 켜져있어서, swiftLint가 특정 프로젝트의 루트를 읽을 수 없다는 오류입니다
Xcode 15부터는 User Script Sandboxing에 따라 Run Script에서 Input files / Output files에 선언한 경로만 읽을 수 있습니다
User Script Sandboxing은 스크립트 단계가 소스 파일이나 중간 빌드 객체에 액세스하는 것을 차단할지에 대한 여부를 결정합니다
이 설정을 NO로 바꾸게 되면,
Run Script가 샌드박스 밖에서 실행되는 것처럼 동작해서 swiftLint가 내부 파일을 자유롭게 읽을 수 있게 됩니다
다만 User Script Sandboxing은 Apple에서 권장하는 방식은 아닙니다
샌드박스를 끄면, 잠재적으로는 보안/안정성 측면의 이점을 포기하는 셈이 됩니다
그러면 어떻게 이 문제를 해결해볼 수 있을까요?
⎮ SPM으로 안전하게 SwiftLint 세팅하기
Xcode 15+에서는 Run Script 대신 SPM의 Build Tool Plugin을 쓰는 방식으로 이를 해결해볼 수 있습니다

둘다 None으로 설정하고, Add Package를 눌러줍니다
TARGETS - Build Phases - Run Build Tool Plug-ins에서 + 버튼을 눌러줍니다

SwiftLintBuildToolPlugin을 Add해줍니다


add 후에 최초 빌드를 하면 다음과 같은 Waring이 나올 수 있습니다

첫번째 에러는 SwiftLint 패키지 안에 SwiftLintCoreMacros의 사용을 허용하지 않아서 뜨는 오류라서,
아래의 Trust & Enable을 클릭해주면 됩니다

두번째 에러도 비슷한 플로우인데, SwiftLintBuildTooPlugin을 사용한다고 해주지 않아서 뜨는 에러입니다
마찬가지로 Trust & Enable을 클릭해주면 됩니다

적용만 잘 되었다면, User Sandbox 설정을 건드리지 않고도 정상 빌드가 됩니다
⎮ SwiftLint 규칙
// 스타일 관련
line_length // 한줄 길이 제한(100~120으로 설정)
trailing_whitespace // 줄 끝에 공백이 있으면 경고
vertical_whitespace // 빈줄을 1줄까지만 허용
vertical_whitespace_between_cases // switch case 사이 공백 관리
opening_brace // { 앞뒤 공백 규칙, 줄바꿈 규칙)
colon // let foo: Int 처럼 콜론 앞뒤 공백
trailing_newline // 파일 마지막에 빈 줄 하나 필수
// 위험 | 안티 패턴 관련
force_cast (as!)
force_try (try!)
force_unwrapping (! 옵셔널 강제 해제)
// 사용하지 않는 코드 관련
unused_optional_binding
unused_closure_parameter // _ in 으로 바꾸라고 경고
unused_import // 사용하지 않는 import 정리하라고 경고
// 네이밍 | 구조 관련
identifier_name // 너무 짧은 변수명 금지(a, b, c) + 예외 리스트
type_name // 타입 이름 길이, 대문자 시작 여부 등
file_length // 파일 길이 제한
type_body_length // 타입 길이 제한
function_body_length // 함수 길이 제한
nesting // if, switch, closure가 너무 깊게 중첩되는 것 제어
위의 규칙 외에도 다양한 규칙이 있습니다
github에서 확인하거나 terminal에서 swiftlint rules 명령어를 입력해서 확인할 수 있습니다
https://github.com/realm/SwiftLint/tree/main/Source/SwiftLintBuiltInRules/Rules
SwiftLint/Source/SwiftLintBuiltInRules/Rules at main · realm/SwiftLint
A tool to enforce Swift style and conventions. Contribute to realm/SwiftLint development by creating an account on GitHub.
github.com
⎮ SwiftLint 규칙 적용하기
SwiftLint에서 규칙을 적용하려면, .swiftLint.yml 파일이 필요합니다
Empy file을 만들고, 파일명을 .swiftLint.yml로 설정합니다

Next를 누르면 .으로 시작하는 숨김파일을 만들 수 있습니다

이제 여기 내부에 규칙을 작성해주면 됩니다(하기는 작성 예시)
# 1. 끄고 싶은 규칙
disabled_rules:
- trailing_whitespace #줄 끝 공백은 신경 쓰지 않는다
- todo #TODO 경고 끄기
- identifier_name
# 2. opt-in 규칙 (기본이 off인데, on할 규칙들)
opt_in_rules:
- opening_brace
- force_unwrapping
- unused_import
- vertical_whitespace
- file_length
# 3. 분석 대상 / 제외 경로
included:
- LintTeset1 # 프로젝트 소스 폴더
# - LintTest1/ViewController.swift #등 구체적으로 작성도 가능
# 4. 각 규칙별 커스터마이징 예
line_length:
warning: 120
error: 200
trailing_whitespace:
ignores_empty_lines: true
ignores_comments: true
vertical_whitespace:
max_empty_lines: 1
이러한 규칙을 적용한 상태에서 테스트를 해보면,
다음과 같이 잘 적용이 되었음을 확인할 수 있습니다

⎮ 결론
SwiftLint의 성능 이슈를 걱정할 수는 있겠지만,
생각해보면 SwiftLint 자체가 빌드 타임에 검사하는 도구라서 앱 런타임 자체의 성능에 영향을 주지는 않습니다
다만, 프로젝트가 커지거나 규칙이 많아진다면 lint가 소모하는 시간(빌드시간)이 길어지기 때문에
꼭 필요한 규칙만 켜는 것이 중요할 것 같습니다
SwiftLint 없이도 협업 규칙을 잘 지켜지고 있다면 그 자체로 이미 좋은 팀입니다.
하지만 새롭게 합류하는 사람도 빠르게 팀 스타일에 적응해야 하거나,
리뷰어가 '공백, 줄 길이' 같은 것에 시간을 덜 쓰게 하고 싶다면
미리 SwiftLint를 도입하는 것도 많은 도움이 될 것 같습니다
'Swift > 기초' 카테고리의 다른 글
| 39. 스위프트 기초 문법[Modeling(5) - Camp 모델 개선] (0) | 2025.02.18 |
|---|---|
| 38. 스위프트 기초 문법[Modeling(4) - Camp 모델링] (0) | 2025.02.17 |
| 37. 스위프트 기초 문법[Modeling(3)] (0) | 2025.02.17 |
| 36. 스위프트 기초 문법[Modeling(2) - Formatters] (0) | 2025.02.11 |
| 35. 스위프트 기초 문법[Modeling(1) - 모델링 기초와 다양한 속성들] (0) | 2025.02.11 |