Clean Code - cleancodeclass/cleancode_theory GitHub Wiki

CleanCode λž€ 무엇인가?

Bjarne Stroustrup 의 μ •μ˜ (inventor of C++)

I like my code to be elegant and efficient. The logic should be straightforward and make it hard for bugs to hide, the dependencies minimal to ease maintenance, error handling complete according to an articulated strategy, and performance close to optimal so as not to tempt people to make the code messy with unprincipled optimizations. Clean code does one thing well.

1

Grady Booch 의 μ •μ˜ (inventor of UML)

Clean code is simple and direct. Clean code reads like well-written prose. **Clean code never obscures the designers intent ** but rather is full of crisp abstractions and straightforward lines of control.

1

우리의 μ •μ˜

λͺ¨λ“  νŒ€μ›μ΄ 이해(understandability)ν•˜κΈ° 쉽도둝 μž‘μ„±λœ μ½”λ“œ

  • μ˜μ‘΄μ„±μ΄ 적어 λ‹¨μˆœν•˜κ³ , ν…ŒμŠ€νŠΈμ½”λ“œλ‘œ κ²€μ¦λœ μ½”λ“œ
  • μ½”λ“œλ₯Ό ν•΄μ„ν•˜λŠ” μ‹œκ°„κ³Ό μˆ˜μ •ν•˜λŠ” μ‹œκ°„μ˜ λΉ„μœ¨μ€ 10(read) : 1 (write)
  • λŒ€λΆ€λΆ„μ˜ 결함은 κΈ°μ‘΄ μ½”λ“œ μˆ˜μ • μ‹œμ— λ°œμƒλ˜λ―€λ‘œ μ΄ν•΄ν•˜κΈ° μ‰¬μš΄ μ½”λ“œλŠ” 였λ₯˜μ˜ μœ„ν—˜μ„ μ΅œμ†Œν™”ν•¨

1

CleanCodeλ₯Ό μž‘μ„±ν•΄μ•Ό ν•˜λŠ” 이유

1

Clean Code의 μ£Όμš” 원칙

https://www.planetgeek.ch/wp-content/uploads/2014/11/Clean-Code-V2.4.pdf 1 1 1

Clean Code 이둠 λ‚΄μš©

Robert C Martion - Clean Code

Clean Code μ°Έκ³  λ™μ˜μƒ

Clean Code의 μ£Όμš” μ˜μ—­

1

1. Naming

  • μ˜λ„λ₯Ό λΆ„λͺ…νžˆ λ°ν˜€ Naming ν•˜λΌ
  • λ³€μˆ˜λ‚˜ ν•¨μˆ˜μ˜ 클래슀의 쑴재의 μ΄μœ μ™€ μ‚¬μš©λ°©λ²•λ“±μ„ μ•ŒκΈ° μ‰½κ²Œ μž‘μ„±ν•΄μ•Ό ν•œλ‹€
  • μ½”λ“œκ°€ ν•˜λŠ” 일을 μ§μž‘ν•˜κΈ° μ‰½κ²Œ μž‘μ„±ν•΄μ•Ό ν•œλ‹€

//λ‚˜μœ 예
int d; // κ²½κ³Ό μ‹œκ°„
// dλŠ” μ•„λ¬΄λŸ° μ˜λ―Έκ°€ λ“œλŸ¬λ‚˜μ§€λ„ μ•ŠμœΌλ©° κ²½κ³Όμ‹œκ°„μ΄λ‚˜ λ‚ μ§œ μˆ˜λΌλŠ” λŠλ‚Œλ„ λ“€μ§€ μ•ŠλŠ”λ‹€.

//쒋은 예
int elapsedTimeInDays;
int daysSinceCreation;
int fileAgeInDays;
// ν•΄λ‹Ή λ³€μˆ˜κ°€ μ–΄λ– ν•œ 역할을 ν•˜λŠ”μ§€ μ•ŒκΈ° 쉽닀.
  • 잘λͺ»λœ 정보λ₯Ό ν”Όν•΄μ„œ Naming ν•˜λΌ.
  • Naming μ‹œμ— 잘λͺ»λœ 의미λ₯Ό 담은 단어λ₯Ό μ‚¬μš©ν•΄μ„œλŠ” μ•ˆλœλ‹€.
  • μ„œλ‘œ ν‘μ‚¬ν•œ 이름이λ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šλ„λ‘ μ£Όμ˜ν•œλ‹€.

//λ‚˜μœ 예
//계정 그룹을 ν‘œν˜„ν•˜κ³ μž ν–ˆμ§€λ§Œ List의 μ˜λ―Έκ°€ 잘λͺ» 전달될 수 μžˆλ‹€.
 accountList
//ν‘μ‚¬ν•œ 이름은 ν˜Όλ™μ„ μ€„μˆ˜ μžˆλ‹€.
 XYZControllerForEfficientHandllingOfStrings , XYZControllerForEfficientStorageOfStrings (ꡬ뢄이 쉽지 μ•Šλ‹€)

//쒋은 예
//계정 그룹을 ν‘œν˜„ν•œλ‹€λ©΄ 
 accountGroup, bunchOfAccouns, ν˜Ήμ€ λ‹¨μˆœνžˆ accounts 라고 λͺ…λͺ…ν•œλ‹€.

1

2. Method

  • ν•¨μˆ˜λŠ” ν•œκ°€μ§€ μ—­ν• λ§Œμ„ μˆ˜ν–‰ν•΄μ•Ό ν•œλ‹€.
    • ν•¨μˆ˜λŠ” ν•œ κ°€μ§€λ₯Ό ν•΄μ•Ό ν•œλ‹€. κ·Έ ν•œ κ°€μ§€λ₯Ό 잘 ν•΄μ•Ό ν•œλ‹€. κ·Έ ν•œ κ°€μ§€λ§Œμ„ ν•΄μ•Ό ν•œλ‹€.
    • 이 λΆ€λΆ„μ—μ„œ λ¬Έμ œκ°€ λœλ‹€λ©΄, 그것은 κ·Έ 'ν•œ κ°€μ§€'κ°€ 무엇인지 μ•ŒκΈ°κ°€ μ–΄λ ΅λ‹€λŠ” 점이닀.
    • 이에 λŒ€ν•΄ κ°„λ‹¨ν•œ νŒμ„ 주자면, μ§€μ •λœ ν•¨μˆ˜ 이름 μ•„λž˜μ„œ 좔상화 μˆ˜μ€€μ΄ ν•˜λ‚˜μΈ λ‹¨κ³„λ§Œ μˆ˜ν–‰ν•œλ‹€λ©΄ κ·Έ ν•¨μˆ˜λŠ” ν•œκ°€μ§€ μž‘μ—…λ§Œ ν•œλ‹€κ³  λ³Ό > 수 μžˆλ‹€.
    • μ–΄μ¨‹κ±°λ‚˜ μš°λ¦¬κ°€ ν•¨μˆ˜λ₯Ό λ§Œλ“œλŠ” μ΄μœ λŠ” 큰 κ°œλ…μ„ λ‹€μŒ 좔상화 μˆ˜μ€€μ—μ„œ μ—¬λŸ¬ λ‹¨κ³„λ‘œ λ‚˜λˆ  μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄μ„œκ°€ μ•„λ‹ˆλ˜κ°€.
    • λ”°λΌμ„œ ν•¨μˆ˜κ°€ 'ν•œ κ°€μ§€'만 ν•˜λŠ”μ§€ νŒλ‹¨ν•˜λ €λ©΄ ν•΄λ‹Ή ν•¨μˆ˜ λ‚΄μ—μ„œ 의미 μžˆλŠ” μ΄λ¦„μœΌλ‘œ λ‹€λ₯Έ ν•¨μˆ˜λ₯Ό μΆ”μΆœν•  수 μžˆλ‹€λ©΄ κ·Έ ν•¨μˆ˜λŠ” μ—¬λŸ¬ μž‘μ—…μ„ ν•˜λŠ” μ…ˆμ΄λ‹€.
  • Switch보닀 λ‹€ν˜•μ„±(polymorphism) μ‚¬μš©
    • switch 문은 μž‘κ²Œ λ§Œλ“€κΈ° μ–΄λ ΅λ‹€. λ˜ν•œ 'ν•œ κ°€μ§€' μž‘μ—…λ§Œ ν•˜λŠ” switch 문도 λ§Œλ“€κΈ° μ–΄λ ΅λ‹€. 본질적으둜 switch 문은 Nκ°€μ§€λ₯Ό μ²˜λ¦¬ν•œλ‹€.

public Money calculatePay(Employee e) throws InvalidEmployeeType {
    switch (e.type) {
        case COMMISSIONED:
            return calculateCommissionedPay(e);
        case HOURLY:
            return calculateHourlyPay(e);
        case SALARIED:
            return calculateSalariedPay(e);
        default:
            throw new InvalidEmployeeType(e.type);
    }
}

μœ„ ν•¨μˆ˜μ—λŠ” λͺ‡ κ°€μ§€ λ¬Έμ œκ°€ μžˆλ‹€. 첫째, ν•¨μˆ˜κ°€ κΈΈλ‹€. μƒˆ 직원 μœ ν˜•μ„ μΆ”κ°€ν•˜λ©΄ 더 κΈΈμ–΄μ§„λ‹€. λ‘˜μ§Έ, 'ν•œ κ°€μ§€' μž‘μ—…λ§Œ μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ”λ‹€. μ…‹μ§Έ, SRP(Single Responsibliity Principle)λ₯Ό μœ„λ°˜ν•œλ‹€. μ½”λ“œλ₯Ό λ³€κ²½ν•  μ΄μœ κ°€ μ—¬λŸΏμ΄κΈ° λ•Œλ¬Έμ΄λ‹€. λ„€μ§Έ, OCP(Open Closed Principle)λ₯Ό μœ„λ°˜ν•œλ‹€. μƒˆ 직원 μœ ν˜•μ„ μΆ”κ°€ν•  λ•Œλ§ˆλ‹€ μ½”λ“œλ₯Ό λ³€κ²½ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€. ν•˜μ§€λ§Œ μ•„λ§ˆ κ°€μž₯ μ‹¬κ°ν•œ 문제라면 μœ„ ν•¨μˆ˜μ™€ ꡬ쑰가 λ™μΌν•œ ν•¨μˆ˜κ°€ λ¬΄ν•œμ • μ‘΄μž¬ν•œλ‹€λŠ” 사싀이닀.

이 문제λ₯Ό ν•΄κ²°ν•œ μ½”λ“œκ°€ μ•„λž˜ μ½”λ“œ 이닀. μ•„λž˜ μ½”λ“œλŠ” switch 문을 좔상 νŒ©ν† λ¦¬μ— 꽁꽁 μˆ¨κΈ΄λ‹€. μ•„λ¬΄μ—κ²Œλ„ 보여주지 μ•ŠλŠ”λ‹€.

νŒ©ν† λ¦¬λŠ” switch 문을 μ‚¬μš©ν•΄ μ μ ˆν•œ Employee νŒŒμƒ 클래슀의 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•œλ‹€.; calculatePay, isPayday, deliverPay λ“±κ³Ό 같은 ν•¨μˆ˜λŠ” Employee μΈν„°νŽ˜μ΄μŠ€λ₯Ό 거쳐 ν˜ΈμΆœλœλ‹€.

그러면 λ‹€ν˜•μ„±μœΌλ‘œ 인해 μ‹€μ œ νŒŒμƒ 클래슀의 ν•¨μˆ˜κ°€ μ‹€ν–‰λœλ‹€.


public abstract class Employee {
    public abstract boolean isPayday();
    public abstract Money calculatePay();
    public abstract void deliverPay(Money pay);
}

public interface EmployeeFactory {
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType;
}

public class EmployeeFactoryImpl implements EmployeeFactory {
    public Employee makeEmployee(EmployeeRecord r) throws InvalidEmployeeType {
        switch (r.type) {
            case COMMISSIONED:
                return new CommissionedEmployee(r);
            case HOURLY;
                return new HourlyEmployee(r);
            case SALARIED:
                return new SalariedEmployee(r);
            default:
                throw new ImvalidEmployeeType(r.type);
        }
    }
}
  • ν•¨μˆ˜ 인수 μ΅œμ†Œν™”
    • 가급적이면 4개 μ΄μƒμ˜ 인자λ₯Ό ν”Όν•˜λ„λ‘ ν•œλ‹€.

3. Comment

  • μ£Όμ„μœΌλ‘œ λ‚˜μœ μ½”λ“œλ₯Ό λ³΄μ™„ν•˜μ§€ 말고, μ½”λ“œλ‘œ μ˜λ„λ₯Ό ν‘œν˜„ν•˜λΌ.
  • λ‚˜μœ 주석
    • νŠΉλ³„ν•œ 이유 없이 의무감으둜 λ‹€λŠ” 주석
    • μ½”λ“œμ˜ λ‚΄μš©μ„ κ·ΈλŒ€λ‘œ λ°˜λ³΅ν•˜λŠ” 쀑볡적인 주석 (javadoc 포함)
    • μ£Όμ„μœΌλ‘œ 처리된 μ½”λ“œ: λŒ€λΆ€λΆ„μ΄ μ£Όμ„μœΌλ‘œ 제거된 μ½”λ“œλŠ” λ‹€μ‹œ μ‚¬μš©λ˜μ§€ μ•ŠλŠ”λ‹€.
  • 쒋은 주석
    • 법적인 주석 (μ €μž‘κΆŒ, μ‚¬μš©κΆŒ λ“±)
    • ꡬ체적인 정보와 μ˜λ„λ₯Ό μ„€λͺ…ν•˜λŠ” 주석
    • κ²°κ³Όλ₯Ό κ²½κ³ ν•˜λŠ” 주석 (eg: β€œμ—¬μœ  μ‹œκ°„μ΄ μΆ©λΆ„ν•˜μ§€ μ•Šλ‹€λ©΄ μ‹€ν–‰ν•˜μ§€ λ§ˆμ‹­μ‹œμ˜€.”)
    • TODO, 곡개 API에 λŒ€ν•œ Javadocs λ“± 1

4. Style

  • μ μ ˆν•œ ν–‰ 길이λ₯Ό μœ μ§€ν•˜λΌ.(빈 행을 μΆ”κ°€ν•˜λ„λ‘ ν•œλ‹€.)

package fitnesse.wikitext.widgets;

import java.util.regex.*;

public class BoldWidget extends ParentWidget {
    public static final String REGEXP = "'''.+?'''";
    private static final Pattern pattern = Pattern.compile("'''(.+?)'''", 
        Pattern.MULTILINE + Pattern.DOTALL
    );

    public BoldWidget(ParentWidget parent, String text) throws Exception { 
        super(parent);
        Matcher match = pattern.matcher(text);
        match.find();
        addChildWidgets(match.group(1)); 
    }

    public String render() throws Exception { 
        StringBuffer html = new StringBuffer(""); 
        html.append(childHtml()).append(""); 
        return html.toString();
    } 
}
  • κ΄€λ ¨ν•­λͺ©κ°„μ˜ 거리λ₯Ό μ΅œμ†Œν™”ν•œλ‹€.
    • λ³€μˆ˜λŠ” μ‚¬μš©ν•˜λŠ” μœ„μΉ˜μ— μ΅œλŒ€ν•œ κ°€κΉŒμ΄ μ„ μ–Έν•œλ‹€.
    • 쒅속 κ΄€κ³„μ˜ ν•¨μˆ˜λŠ” μ„Έλ‘œλ‘œ κ°€κΉŒμ΄ λ°°μΉ˜ν•œλ‹€.
  • λ“€μ—¬ μ“°κΈ° μž˜ν•˜κΈ° 1

5. Data Structures

  • μžλ£ŒλŠ” 좔상화λ₯Ό 톡해 λ‚΄λΆ€ κ΅¬ν˜„ 정보λ₯Ό λ…ΈμΆœν•˜μ§€ 말아야 ν•œλ‹€.

public class Point {
    public double x;
    public double y;
} 

public interface Point {
    double getX();
    double getY();
    void setCartesian(double x, double y));
    double getR();
    double getTheta();
    void setPolar(double r, double theta);
}

6. Class

  • 높은 응집도λ₯Ό μœ μ§€ν•˜λ„λ‘ ν•œλ‹€.
    • ν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€ λ³€μˆ˜κ°€ 적어야 ν•˜λ©°, λ©”μ†Œλ“œκ°€ λ³€μˆ˜λ₯Ό 더 많이 μ‚¬μš©ν•  수둝 응집도가 λ†’λ‹€.
    • 응집도λ₯Ό μœ μ§€ν•˜λ©΄, μž‘μ€ 단일 μ—­ν•  클래슀둜 뢄리가 κ°€λŠ₯.

7. Error Handling

  • Null을 λ°˜ν™˜ν•˜κ±°λ‚˜ νŒŒλΌλ―Έν„°λ‘œ λ„˜κΈ°λŠ” 것은 μ§€μ–‘ν•˜λΌ.(빈 객체 등을 전달)
  • Unchecked Exception을 μ‚¬μš©ν•˜λΌ.
    • Checked Exception은 λΆˆν•„μš”ν•œ μ˜ˆμ™Έ 처리λ₯Ό κ°–κ²Œ 되기 λ•Œλ¬Έμ— λ˜λ„λ‘ μ§€μ–‘ν•˜λΌ. exception
    • ErrorλŠ” μ‹œμŠ€ν…œμ— 비정상적인 상황이 생겼을 λ•Œ λ°œμƒν•œλ‹€. μ΄λŠ” μ‹œμŠ€ν…œ λ ˆλ²¨μ—μ„œ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ— μ‹¬κ°ν•œ μˆ˜μ€€μ˜ 였λ₯˜μ΄λ‹€. λ”°λΌμ„œ κ°œλ°œμžκ°€ 미리 μ˜ˆμΈ‘ν•˜μ—¬ μ²˜λ¦¬ν•  수 μ—†κΈ° λ•Œλ¬Έμ—, μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 였λ₯˜μ— λŒ€ν•œ 처리λ₯Ό μ‹ κ²½ μ“°μ§€ μ•Šμ•„λ„ λœλ‹€.
    • μ˜ˆμ™Έ(Exception)λŠ” κ°œλ°œμžκ°€ κ΅¬ν˜„ν•œ λ‘œμ§μ—μ„œ λ°œμƒν•œλ‹€. 즉, μ˜ˆμ™ΈλŠ” λ°œμƒν•  상황을 미리 μ˜ˆμΈ‘ν•˜μ—¬ μ²˜λ¦¬ν•  수 μžˆλ‹€. 즉, μ˜ˆμ™ΈλŠ” κ°œλ°œμžκ°€ μ²˜λ¦¬ν•  수 있기 λ•Œλ¬Έμ— μ˜ˆμ™Έλ₯Ό κ΅¬λΆ„ν•˜κ³  그에 λ”°λ₯Έ 처리 방법을 λͺ…ν™•νžˆ μ•Œκ³  μ μš©ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€. exception type

8. Unit Tests

  • ν…ŒμŠ€νŠΈμ½”λ“œ μž‘μ„± 및 , 지속적인 μœ μ§€λ₯Ό 톡해 μ½”λ“œμ— λŒ€ν•œ μœ μ—°μ„±, μœ μ§€λ³΄μˆ˜μ„± 및 μž¬μ‚¬μš©μ„±μ„ ν™•λ³΄ν•œλ‹€.
  • κΉ¨λ—ν•œ ν…ŒμŠ€νŠΈμ˜ λ‹€μ„― κ°€μ§€ 원칙(F.I.R.S.T)
    • Fast : ν…ŒμŠ€νŠΈλŠ” 빨라야 ν•œλ‹€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ 자주 돌릴 엄두λ₯Ό λͺ»λ‚΄κ³ , κ²°κ΅­ λΆˆν•„μš”ν•œ ν…ŒμŠ€νŠΈκ°€ λœλ‹€.
    • Independent : 각 ν…ŒμŠ€νŠΈλŠ” μ„œλ‘œ μ˜μ‘΄ν•˜λ©΄ μ•ˆλœλ‹€. 의쑴적인 경우 μ‹€νŒ¨μ˜ 원인 νŒŒμ•…μ΄ μ–΄λ ΅λ‹€.
    • Repeatable : ν…ŒμŠ€νŠΈλŠ” μ–΄λ–€ ν™˜κ²½μ—μ„œλ„ 반볡 μ‹€ν–‰ κ°€λŠ₯ν•΄μ•Ό ν•œλ‹€.
    • Self-Validating : ν…ŒμŠ€νŠΈ boolean κ°’μœΌλ‘œ κ²°κ³Όλ₯Ό λ‚΄μ•Ό ν•œλ‹€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄, μžλ™ν™”μ— 걸림돌이 λœλ‹€.
    • Timely : ν…ŒμŠ€νŠΈλŠ” μ μ‹œμ— μž‘μ„±ν•΄μ•Ό ν•œλ‹€. μ‹€μ œ μ½”λ“œ 직전에 μž‘μ„±ν•΄μ•Ό μ μ ˆν•œ μ½”λ“œκ°€ μž‘μ„±λœλ‹€.
⚠️ **GitHub.com Fallback** ⚠️