개발을 하다 보면, "내가 작성하고 있는 코드가 과연 좋은 코드인가?"라는 고민에 빠질 때가 있는데
이 질문에 대한 답을 찾기 위해 많은 개발자들이 '클린 코드 (Clean Code)' 서적을 많이 추천해줘서 나도 읽어보았다!
이 글에서는 클린 코드를 읽으면서 알게된 핵심 개념과 좋은 코드를 작성하기 위한 방법을 정리하고자 합니다.
코드의 변수, 함수, 클래스 등의 이름은 코드의 의도를 명확하게 표현할 수 있어야 합니다.
이름만으로도 해당 코드가 어떤 일을 수행하는지 쉽게 예측할 수 있다면, 더 나은 코드라고 할 수 있습니다.
boolean flag = true;
boolean isUserLoggedIn = true;
의미 없는 약어나 애매한 이름 대신, 명확한 이름을 사용하세요.
복잡한 조건문은 읽기 어렵고 유지보수가 힘듭니다.
조건을 명확하게 드러내는 함수로 감싸면 코드의 가독성이 크게 향상됩니다.
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) {
// 복지 혜택 자격 확인
}
if (employee.isEligibleForFullBenefits()) {
// 복지 혜택 자격 확인
}
생성자를 오버로딩하면 인수의 의미가 불분명해질 수 있습니다.
이럴 때 정적 팩토리 메서드를 사용하여 명확한 이름을 부여하는 것이 좋습니다.
Student student = new Student("James", 85);
Student student = Student.withGrade("James", 85);
서술적인 이름은 코드를 이해하기 쉽게 만들고, 리팩토링도 더 수월하게 만듭니다.
이름 짓기 규칙:
예시:
public void includeSetupAndTeardownPages() { ... }
public void includeSetupPages() { ... }
public void includeSuiteSetupPage() { ... }
public void includeSetupPage() { ... }
하나의 함수는 명령(수행)과 조회(확인) 중 하나의 역할만 담당해야 합니다.
두 역할을 동시에 수행하면 코드가 혼란스러워집니다.
나쁜 예:
public boolean set(String attribute, String value);
if (set("username", "coco")) { ... }
좋은 예:
public boolean attributeExists(String attribute);
public boolean set(String attribute, String value);
if (attributeExists("username")) {
set("username", "coco");
}
오류 코드를 반환하면 중첩된 조건문이 발생해 코드가 복잡해집니다.
예외 처리를 사용하면 더 간결한 코드를 작성할 수 있습니다.
나쁜 예:
public Status deletePage(Page page) {
if (deletePage(page) == E_OK) {
if (registry.deleteReference(page.name) == E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) == E_OK) {
log.info("page deleted");
return E_OK;
} else {
log.error("config key not deleted");
}
} else {
log.error("reference not deleted");
}
} else {
log.error("page not deleted");
}
return E_ERROR;
}
좋은 예:
public void deletePage(Page page) {
try {
deletePageAndAllReferences(page);
} catch (Exception e) {
log.error(e.getMessage());
}
}
public void deletePageAndAllReferences(Page page) throws Exception {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
디미터 법칙은 한 객체가 다른 객체의 내부 구조를 직접 참조하지 않도록 하는 원칙입니다.
내부 구조를 노출하면 결합도가 높아지며, 유지보수가 어려워집니다.
나쁜 예:
String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();
좋은 예:
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir();
String outputDir = scratchDir.getAbsolutePath();