멀티라인 포맷팅 기본
Source: Dev.to
왜 기본적으로 멀티‑라인 포맷팅을 선호하는가
나는 많은 코드를 리뷰하며, 보통 멀티‑라인 포맷팅을 선호한다.
코드가 더 예뻐 보여서가 아니라, 코드 리뷰가 줄‑단위로 이루어지기 때문이다.
정적 분석 도구와 SQL 오류도 줄‑단위로 보고된다.
PS: 대부분의 IDE에서는 빠른 검색이나 명령줄을 통해 파일/줄(예:
FILE:LINE)로 바로 이동할 수 있다.
한 줄만 바뀐 경우는 하나의 내용만 변경된 것으로 보는 것이 이상적이다.
명백해 보이지만, 예시를 통해 그 점을 명확히 할 수 있다.
압축된 코드의 문제점
- 리뷰어는 어떤 마법 같은 추상적인 세계에서 “코드” 자체를 검토하지 않습니다.
- 리뷰어는 diff를 검토하며, diff는 라인 기반입니다.
여러 개의 독립적인 결정이 같은 라인에 존재하면, 모든 변경 사항을 검증하기가 더 어려워집니다. 작은 변경이 리뷰를 통과하는 이유는 리뷰어가 게으르기 때문이 아니라 (때때로는 그렇지만), 포맷팅이 리뷰를 필요 이상으로 어렵게 만들기 때문입니다.
Source: …
Examples
JavaScript
Bad
const user = users.find(user => user.id === selectedUserId && user.active && !user.deleted);
Better
const user = users.find(
user =>
user.id === selectedUserId
&& user.active
&& !user.deleted
);
이제 리뷰어는 누가 다음을 바꿨는지 확인할 수 있습니다:
user.id === selectedUserId
또는
user.active
또는
!user.deleted
한 논리 조건당 한 줄.
SQL
Bad
SELECT id, name, email, created_at FROM users WHERE active = 1 AND deleted_at IS NULL ORDER BY created_at DESC;
Better
SELECT
id,
name,
email,
created_at
FROM users
WHERE active = 1
AND deleted_at IS NULL
ORDER BY created_at DESC;
이제 email을 private_email으로 바꾸거나, 필터를 추가하거나, 컬럼을 제거할 때 한 줄만 건드리면 됩니다. diff가 마치 누군가 SQL을 블렌더에 넣은 것처럼 보이지 않게 됩니다.
Conditions
Bad
if ($user !== null && $user->isActive() && !$user->isDeleted() && $user->hasPermission('admin')) {
// ...
}
Better
if (
$user !== null
&& $user->isActive()
&& !$user->isDeleted()
&& $user->hasPermission('admin')
) {
// ...
}
각 조건을 독립적으로 검토할 수 있습니다.
&& $user->hasPermission('admin')
를
&& $user->hasPermission('user')
로 바꾸는 것이 이제 명확해집니다 – 단순한 포맷팅 변경이 아니라 실제 동작 변경이기 때문입니다.
HTML
Bad
Better
이제 required, autocomplete, class, value 등의 변경이 명확히 보이며, 가로줄이 길어지는 것을 피할 수 있습니다.
Function Parameters
Bad
$user = $userRepository->findActiveUserByEmail($email, true, false, ['admin', 'editor']);
Better
$user = $userRepository->findActiveUserByEmail(
email: $email,
includeDisabled: true,
includeDeleted: false,
roles: [
'admin',
'editor',
],
);
- 장점:
- 검토가 쉬워집니다.
- “미스터리 불리언” 인자(
true, false)를 없앨 수 있습니다. - 매우 표현력이 풍부합니다 – 미래의 고고학자들이 감사할 것입니다.
Arrays
Bad
$config = ['enabled' => true, 'timeout' => 30, 'retries' => 3, 'log_errors' => true];
Better
$config = [
'enabled' => true,
'timeout' => 30,
'retries' => 3,
'log_errors' => true,
];
이제 각 키/값 쌍이 자체 라인에 존재하므로 추가·제거·수정이 깔끔하고 잡음 없이 이루어집니다.
Config Blocks
Bad
$options = ['cache' => true, 'ttl' => 3600, 'debug' => false, 'strict' => true];
Better
$options = [
'cache' => true,
'ttl' => 3600,
'debug' => false,
'strict' => true,
];
구성 변경은 리뷰 명료성이 가장 중요한 곳입니다; 하나의 플래그가 전체 시스템에 영향을 미칠 수 있기 때문에, 긴 가로줄에 숨겨서는 안 됩니다.
Method Chains
Bad
$result = $queryBuilder
->select('id', 'name')
->from('users')
->where('active = 1')
->orderBy('created_at', 'DESC')
->limit(10)
->fetchAll();
Better
$result = $queryBuilder
->select('id', 'name')
->from('users')
->where('active = 1')
->orderBy('created_at', 'DESC')
->limit(10)
->fetchAll();
(이 경우 체인이 이미 메서드당 한 줄로 구성되어 있어 선호되는 스타일입니다.)
요약
각 논리적 조각이 자체 라인에 배치되도록 코드를 포맷팅하면:
- 차이(diff) 가독성을 향상시킵니다.
- 단일 목적 변경을 명확하게 합니다.
- 리뷰 과정에서 실수로 발생하는 버그가 넘어갈 가능성을 줄입니다.
이 습관을 채택하면 리뷰어(및 향후 유지보수자)에게 감사받을 것입니다.
예시: 쿼리 빌더 체인
전
active = 1')->orderBy('created_at', 'DESC')->limit(50);
더 나은
$result = $queryBuilder
->select('id', 'name')
->from('users')
->where('active = 1')
->orderBy('created_at', 'DESC')
->limit(50);
이제 각 쿼리 작업이 자체 라인에 배치되어, 리뷰어가 정확히 무엇이 변경됐는지 쉽게 확인할 수 있습니다.
변경 찾기
->where('active = 1')
또는
->limit(50)
이는 특히 누군가가 조용히 50을 5000으로 바꾸어 데이터베이스가 갑자기 업무 환경에 대한 불만을 제기하기 시작할 때 중요합니다.
실제 규칙
한 줄에 여러 독립적인 의미가 포함될 경우 다중 라인 포맷을 선호합니다.
전형적인 후보:
- JavaScript 표현식
- SQL 쿼리
- 조건문
- HTML 속성
- 함수 매개변수
- 배열
- 설정 블록
- 메서드 체인
이것은 모든 줄을 반드시 나눠야 한다는 의미는 아닙니다.
$isActive = true;
이는 별도의 형식이 필요하지 않습니다.
우리는 검토 가능성을 위해 포맷팅하는 것이지, 공백 종교를 시작하려는 것이 아닙니다.
컴팩트한 코드는 자동으로 읽기 쉬운 것이 아니다
컴팩트한 코드는 하나의 아이디어를 담고 있을 때 읽기 쉬울 수 있다.
하지만 여러 결정을 한 줄에 압축하면 문제가 된다.
리뷰어는 간단한 질문에 빠르게 답해야 한다:
- 무엇이 바뀌었는가?
- 변경이 안전한가?
- 변경된 라인이 한 가지 일을 하고 있는가?
- 작성자가 동작을 포맷 잡음 안에 숨겼는가?
다중 라인 포맷팅이 도움이 되는 이유
- 잡음을 줄인다.
- 의도를 명확히 드러낸다.
- 리뷰를 날카롭게 만든다.
최종 생각
읽기 쉬운 차이점이 영리한 포맷팅을 이긴다.
항상.