HotfixHero 코드 선언문: 지켜야 할 일곱 규칙
Source: Dev.to
Hotfixhero 코드 선언문
살아가야 할 일곱 가지 규칙
코딩은 단순히 기계에게 명령을 내리는 것이 아니라, 사람에게 가치를 전달하는 일입니다. 이 선언문은 우리 모두가 더 나은 코드를 작성하고, 더 나은 개발자가 되기 위해 따를 수 있는 일곱 가지 원칙을 제시합니다.
1. 사람을 위한 코드를 쓰라
코드는 읽는 사람을 위해 존재합니다.
- 변수와 함수 이름은 의미가 명확해야 합니다.
- 복잡한 로직은 작은, 이해하기 쉬운 단위로 나누세요.
- 주석은 “왜”를 설명하고, “무엇을”은 코드 자체가 말하도록 합니다.
2. 단순함을 추구하라
복잡한 해결책은 버그와 유지보수 비용을 늘립니다.
- KISS 원칙(Keep It Simple, Stupid)을 기억하세요.
- 불필요한 추상화와 과도한 설계는 피합니다.
- 가능한 한 직관적인 구현을 선택하세요.
3. 테스트를 일찍, 자주, 자동화하라
테스트는 코드 품질을 보장하는 가장 확실한 방법입니다.
- 테스트‑드리븐 개발(TDD)을 적용해 보세요.
- CI 파이프라인에 자동 테스트를 포함시켜, 코드가 병합될 때마다 검증되도록 합니다.
- 실패하는 테스트는 즉시 고쳐야 합니다.
4. 리팩터링은 필수다
코드가 동작한다는 이유만으로 그대로 두지 마세요.
- 주기적인 리팩터링을 스프린트에 포함시키세요.
- 중복을 제거하고, 가독성을 높이며, 성능을 개선합니다.
- 리팩터링 전후에 테스트가 통과하는지 반드시 확인합니다.
5. 문서는 코드와 함께 살아라
문서는 코드와 동기화되어야 합니다.
- README, 위키, API 문서는 최신 상태를 유지하세요.
- 코드 주석은 핵심 로직을 설명하는 데에만 사용하고, 상세 설명은 별도 문서에 기록합니다.
- 변경 로그(CHANGELOG)를 꾸준히 업데이트해 팀 전체가 변화를 추적할 수 있게 합니다.
6. 피드백을 환영하라
다른 사람의 시각은 새로운 인사이트를 제공합니다.
- 코드 리뷰는 비판이 아니라 성장의 기회로 생각하세요.
- 건설적인 피드백을 주고받으며, 최선의 구현을 찾아갑니다.
- 팀 내에서 지식 공유 세션을 정기적으로 개최합니다.
7. 끊임없이 배우고 성장하라
기술은 빠르게 변합니다. 멈추지 말고 계속 발전하세요.
- 최신 언어 기능, 프레임워크, 도구를 꾸준히 탐구합니다.
- 오픈소스 프로젝트에 기여하거나, 블로그에 학습 내용을 정리합니다.
- 실패를 두려워하지 말고, 실수에서 교훈을 얻어 다음에 적용합니다.
마무리
이 일곱 가지 규칙은 코드 품질을 높이고, 팀 협업을 원활하게 하며, 개인 성장을 촉진합니다. 매일 작은 습관으로 실천한다면, 어느새 더 나은 개발자가 되어 있을 것입니다.
“코드는 살아있는 문서다. 우리가 어떻게 다루느냐에 따라 그 가치는 달라진다.” – Hotfixhero 팀
소개
당신의 입장을 이해합니다. 팀에게 부끄러움을 주지 않기 위한 기술 사양을 원하시는군요. 좋습니다. 규모가 커지고 만성적인 두통을 유발하지 않는 코드를 작성하는 것은 마법이 아니라 규율에 달려 있습니다. 복잡한 패턴은 잠시 제쳐두고—먼저 기본을 마스터하세요.
제가 따르는 일곱 가지 계명이 있습니다. 이를 읽고, 구현하고, 어쩌면, 당신의 코드 리뷰가 전쟁 범죄 보고서처럼 보이지 않을 수도 있습니다.
1. DRY (반복 금지)
모든 로직, 비즈니스 규칙, 데이터 정의는 정확히 한 곳에만 존재해야 합니다. 복사‑붙여넣기를 하면 코딩이 아니라 기술 부채를 만드는 것입니다. 버그를 수정하는 비용은 자신을 반복한 횟수만큼 곱해집니다. 이는 끔찍한 ROI입니다.
Bad Example (Duplicate Validation)
function createUser(data) {
if (data.password.length // The goal is to solve the problem, not win a Turing Award for the most convoluted solution. Simple code is cheaper to maintain, easier to test, and less likely to introduce subtle bugs. Your complexity doesn't impress anyone but junior developers.
Bad Example (Overly Complex Conditional)
function getDiscount(user) {
let status = user.isPremium ? 0.20 :
(user.totalOrders > 5 && user.joinedYear 10 ? 0.10 : 0;
// Now try debugging that nested ternary hell at 3 AM.
return status;
}
HH Way (Using Clear Logic)
function getDiscount(user) {
if (user.isPremium) {
return 0.20;
}
if (user.totalOrders > 5 && user.joinedYear 10) {
return 0.10;
}
return 0; // The default, simple case
}
Source:
3. YAGNI (You Aren’t Gonna Need It)
다음 해에 제품 소유자가 무엇을 요구할지 추측하지 마세요. 오늘 필요한 것만 구축하세요. 현재 문제를 해결하지 않는 모든 코드는 낭비된 시간이며 불필요한 복잡성을 초래합니다.
나쁜 예 (미래 기능을 위한 사전 구축)
# 현재 요구사항은 'File' 저장소만 필요합니다.
# 개발자는 혹시 모를 상황을 대비해 'S3'와 'Azure'용 훅을 추가합니다.
class StorageManager:
def __init__(self, storage_type='FILE'): # 클래스나 함수는 **하나의** 변경 이유만 가져야 합니다. 함수가 데이터를 가져오고, 포맷을 변환하고, 이메일을 보내는 역할을 동시에 한다면 이는 과도한 책임입니다. 이메일 포맷이 바뀔 때 데이터를 가져오는 함수가 변경될 필요는 없습니다.
나쁜 예 (God Function)
function processAndFormatUserData(id) {
// 1. 데이터 가져오기 (변경 이유: 데이터베이스 스키마)
const user = database.fetchUser(id);
// 2. 나이 계산 (변경 이유: 계산 로직)
const age = new Date().getFullYear() - new Date(user.dob).getFullYear();
// 3. 출력 포맷팅 (변경 이유: UI/API 요구사항)
return { id: user.id, fullName: `${user.first} ${user.last}`, age };
}
HH 방식 (책임 분리)
// 1. 데이터 조회
function fetchUserFromDB(id) {
return database.fetchUser(id);
}
// 2. 비즈니스 로직 / 계산
function calculateAge(dob) {
return new Date().getFullYear() - new Date(dob).getFullYear();
}
// 3. 포맷팅 / 프레젠테이션
function formatUserPresentation(user) {
return {
id: user.id,
fullName: `${user.first} ${user.last}`,
age: calculateAge(user.dob) // 집중된 로직 호출
};
}
5. 관심사의 분리
애플리케이션을 가능한 한 겹치지 않도록 별개의 기능으로 나눕니다. 데이터 접근 계층은 HTTP 요청 헤더에 대해 알 필요가 없으며, 컨트롤러는 복잡한 포맷팅 로직을 포함해서는 안 됩니다.
나쁜 예시 (데이터 접근과 비즈니스 로직 혼합)
// Inside a Web Controller/Endpoint
@GetMapping("/users/{id}")
public UserDetails getUserDetails(@PathVariable Long id) {
// Concern 1: Database Access is mixed here
UserEntity user = entityManager.find(UserEntity.class, id);
// Concern 2: Business Logic is mixed here
if (user.getBalance() // Optimize only when you have evidence that a piece of code is a bottleneck. Writing clever, low‑level loops for the sake of “speed” often sacrifices readability and maintainability.
나쁜 예시 (가독성을 해치는 불필요한 저수준 루프)
// Bad: Using a manual `for` loop where a higher‑level method would be clearer
let result = [];
for (let i = 0; i item.active);
결론
이 기본들을 마스터하면, 자신의 코드와 싸우는 데 드는 시간을 훨씬 줄이고 가치를 제공하는 데 더 많은 시간을 할애할 수 있습니다. 위의 원칙들은 시대를 초월한 것이므로, 일관되게 적용하면 미래의 자신(그리고 팀원들)이 감사할 것입니다.
마이크로 최적화를 위한 길이 감소
네이티브 메서드보다 가독성이 떨어지고, 최신 엔진은 map과 forEach를 동일하게 최적화합니다.
let i = items.length;
while (i--) {
processed.push(items[i].toUpperCase());
}
HH 방식 (가독성 및 유지보수성)
좋음: 의도가 명확하고, 최적화된 내장 메서드에 의존합니다.
// Using the built-in `map` method
const processed = items.map(item => item.toUpperCase());
Law of Demeter (Principle of Least Knowledge)
“Don’t talk to strangers.”
객체는 자신이 만든 객체, 매개변수, 속성 등 즉각적인 친구와만 통신해야 합니다.
메서드 체인을 통해 깊은 내부 구조에 접근하면 코드가 결합되어 취약해집니다.
Bad Example (Method‑Chaining Violation)
// `user` 객체에게 `wallet`을 요청하고, 그 `wallet`에게 `card`를 요청한 뒤,
// `card`에게 `security code`를 요청하고 있습니다. 지식이 과도합니다.
String code = user.getWallet()
.getPrimaryCard()
.getSecurityCode();
HH Way (Delegation)
// `user`에게 동작을 수행하도록 요청만 합니다. `user` 객체가 내부 구조를 처리합니다.
String code = user.getSecurityCodeForPrimaryCard();