✔️ 작게 만들어라
✔️ 한가지만 해라
→ 내부에 다른 함수로 추출할 수 있는 section이 더 있는가?
✔️ 서술적인 이름 사용 (동사구 활용)
ex) isOrderable(), hasAvailableProduct
예제 코드
static string renderPageWithSetupsAndTeardowns(PageData pageData, bool isSuite) {
bool isTestPage = pageData.hasAttribute("Test");
// 테스트 페이지 확인
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
string newPageContent;
// 설정 페이지
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
// 해제 페이지
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent);
}
// HTML로 렌더링
return pageData.getHtml();
}
하나의 함수에서 3가지 수행
1. 테스트 페이지인지 판단
2. 설정 페이지와 해제 페이지 넣기
3. 페이지를 HTML로 렌더링
함수 추출이 가능한지 의심하고
함수당 3~5줄 이내로 권장
static string renderPageWithSetupsAndTeardowns(PageData pageData, bool isSuite) {
if (isTestPage(pageData))
{
includeSetupAndTeardownPages(pageData, isSuite);
}
return pageData.getHtml();
}
✔️ 적절한 함수 인자 개수
• 일반적으로 인자가 적을수록 좋다.
인자 순서를 기억할 필요가 없기 때문이다.
ex) strcpy(target, source);
target, source 순서를 외워야 하지만
그 마저도 뒤바뀌는 경우가 있다.
• 경우에 따라서는 단항/이항 함수가 좋을 수 있다.
ex) new Point(x, y);
• 3개 이상은 가능하면 피하는 것이 좋다.
• 인수가 2~3개 필요하다면 일부를 클래스 변수로 대체하는 것도 좋다.
• 출력 인수가 많을 경우 객체 / pair / tuple 사용이 좋다.
(예제) stream 먼저? name 먼저?
writeField(stream, name); → stream.writeField(name);
(예제) 기대값 먼저? 실제값 먼저?
assertEquals(expected, actual); → assertExpectedEqualsActual(expected, actual)
✔️ 부수 효과를 일으키지 마라!
class UserValidator {
private:
Cryptographer cryptographer;
public:
bool checkPassword(string userName, string password) {
UserPtr pUser = UserGateway::findByName(userName);
if (nullptr != pUser) {
const auto& codedPhrase = pUser->getPhraseEncodedByPassword();
string phrase = cryptographer.decrypt(codedPhrase, password);
if ("Valid Password" == phrase) {
Session::init(); // 함수명과 맞지 않는 부수효과
return true;
}
}
return false;
}
};
함수명 checkPassword는 "비밀번호 확인" 하는 목적이다.
내부 로직에서 세션 초기화까지 하는 것은 부수효과이다.
checkPasswordAndInitSession으로 변경하는게 좀 더 명확하다.
길고 서술적인 이름이
짧고 어려운 이름/주석보다 좋다.
✔️ 명령과 조회 분리
객체 상태 변경 or 객체 정보 반환 중 하나만 해야한다.
// 속성 값 설정하고 bool 타입까지 반환해서는 안된다.
bool set(string attribute, string value);
// 언뜻보면 괜찮아 보이지만 명령과 조회가 같이 있는 형태
if(set(“username”, “unclebob”))
하나의 기능을 하는 함수로 명확히 분리
if (attributeExists("username")) {
setAttribute("username", "hyun");
}
✔️ 오류 코드보다 예외 사용
if (deletePage(page) == E_OK) {
if (registry.deleteReference(page.name) == E_OK) {
if (configKeys.deleteKey(page.name.makeKey()) == E_OK) {
logger.log("page deleted");
}
else {
logger.log("configKey not deleted");
}
}
else {
logger.log("deleteReference from registry failed");
}
}
else {
logger.log("delete failed");
return E_ERROR;
}
아래 코드는 "명령과 조회 분리"을 위반하는 형태다.
deletePage(page) == E_OK
(오류 유형이 많아 진다면 중첩도 많아진다.)
try/catch를 사용하면 오류 처리 코드가
원래 코드에서 분리되므로 코드가 깔끔해 진다.
try {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
} catch (const exception& e) {
logError(e);
}
try, catch 블록에 있는 로직을 함수로 추출하여
내려가기 규칙에 맞게 작성하는 것도 좋다.
* 오류 처리도 한가지 작업(함수)
void delete(const Page& page) {
try {
deletePageAndAllReferences(page);
} catch (const exception& e) {
logError(e);
}
}
// 정상 동작 함수
void deletePageAndAllReferences(const Page& page) {
deletePage(page);
registry.deleteReference(page.name);
configKeys.deleteKey(page.name.makeKey());
}
// 오류 동작 함수
void logError(const exception& e) {
logger.log(e.getMessage());
}
✔️ Switch 문
switch 문을 작게 만들기 어렵다.
본질적으로 N가지를 처리하기 때문이다.
그렇기에 switch문을 완전히 피할 방법은 없다.
팩토리 메소드 패턴 (Factory Method)을 활용하거나
전략 패턴을 사용해서 switch 문을 최소화할 수 있다
✔️ Flag 인수
함수로 Bool 값을 넘기는 경우가 많다.
if (TRUE)
{
...
}
else // FALSE
{
...
}
함수가 여러 가지를 처리한다고 명시한 것과 마찬자지로
true/false에 따라 두 가지 함수로 나누는게 원칙상 맞다.
Q) 그렇다면 아래의 경우는 어떨까?
A) 개인적으로는 로직에 따라서 판단할 문제인 것 같다.
VOID setDMAEngine(bool en)
{
DMAEngine.stateOn = en;
}
참고로, 구조적 프로그래밍 원칙에 따르면
모든 함수와 블록에 입구와 출구가 하나여야 된다.
• 함수에서 return문 1개
• loop안에서 return, break, continue 사용 X
(함수가 충분히 작다면 어느정도 사용 O)
• goto는 절대로 사용 X
'까망 동네 > 클린 코드' 카테고리의 다른 글
[클린코드] 객체와 자료구조 (0) | 2022.07.19 |
---|---|
[클린코드] 형식 (Format) (0) | 2022.07.18 |
[클린코드] 주석 Comment (0) | 2022.07.18 |
[클린코드] 의미 있는 이름 (0) | 2022.07.17 |
클린 코드(Clean Code)란? (0) | 2022.07.17 |
댓글