[Clean Coding] 17.

라을·2024년 12월 9일

Clean Coding

목록 보기
9/10

G18 : Inappropriate Static

static인 것과 아닌 것을 구별해야 함

class A {
	static int f(){}
}

class B extends A {
	static int f(){}
}

A a;
a.f();
a = new B(); //가능
a.f(); // f가 static이기 때문에 A에 있는 f가 호출됨. override 개념이 아님!! 

static은 override가 안된다.

B의 f가 필요하다면

B b;
b.f(); 를 해야하는 것

G19 : 설명적 변수

group1, group2보다 key, value라고 명시해주는 것이 좋은 것!


G20 : 함수 이름의 중요성

함수 이름을 보고 독자는 무엇을 하는 코드인지 잘 떠올릴 수 있어야 하고, 떠올린 내용과 코드의 작동이 일치해야 한다

Date newDate = date.addDaysTo(5);
or
Date newDate = date.increaseByDays(5); //better

만약 함수가 새로운 날짜를 반환하고, 날짜 인스턴스를 변경하지 않는다면

Data newDate = date.daysLater(5);
or
Date newDate = date.daysSince(5);

G21 : 알고리즘을 이해해야 한다

예를 들어, if문을 사용한다면 사용하는 이유가 명확해야한다. 만약 if문을 사용해야하는 것 같다라는 표현을 하거나 하면 더 좋은 것 같다라는 식으로 설명을 해서는 안된다

코드를 책임질 수 있어야 하는 것


G22 : Make Logical Dependencies Physical

formatter 강조!

코드를 입력하세요

G23 : Prefer Polymorphism to Conditional

조건문보다 다형성을 선호해라!
: 소프트웨어 설계에서 조건문(if, switch)을 사용하는 대신 다형성을 활용하는 것이 코드의 확장성과 유지보수성을 높이는 데 유리하다는 원칙이다

  1. 조건문의 단점
  2. 다형성의 장점

코드 분할의 장점


G24: 통상적인 기준을 따를 것


G25 : 숫자보단 이름으로 대체하기


G26 : 꼼꼼하게! 명료하게!


G27 : Structure over Convention


G28 : Encapsulate Conditionals

길게 이해하게 하지 말고 함수로 뽑아내라
stepdown rule & 주석을 없애는 것


G29 : Avoid Negative Conditionals


G30 : 함수는 한 단계의 일만 해야한다

StepDown Rule

public void pay() {
	for (Employee e : employees) {
    	if (e.isPayday()) {
        	Money pay = e.calculatePay();
            e.deliverPay(pay);
        }
    }

}

public void 

이건 약간 over engineering 스러운 코드이다
(전 챕터들 확인하고 다시 작성하기)


G31 : Hidden Temporal Coupling

순서대로 작업하는 것을 강제화하고 싶다면
앞에서 받은 return 값을 밑에서 받아서 쓰도록 하기

public void dive(String reason)	{
	Gradient gradient = saturateGradient();
    List<Spline> splines = reticulateSplines(gradient);
    diveForMoog(splines, reason);
}

G32 : 임의로 작성하지 말기

코드가 커지다보면 안에 작성된 클래스를 끄집어내야하는 경우가 있다

아래 코드는 Calculator가 더이상 ReportViewer에 있을 필요가 없는 것!

안에 있으면 ReportView.Caculator.add(1,4)로 작성해야 하므로 적합하지 않음


G33 : 중복 제거

level+1 이 무엇을 의미하는지 잘 모를 수 있음
-> 설명적 변수(ex.nextLevel)로 저장하여서 이를 재사용하는 것이 나음


G35 : Keep Configurable Data at High Levels (설정 가능한 데이터를 높은 수준에서 유지)

함수 구석구석에 있으면 안되고 설정 변수는 모두가 찾게 되는 변수이기 때문에 찾기 용이하기 위해 가장 높은 레벨에 작성해줘야 한다

//나쁜 코드 예시
public class MainApp {
    ...
    public int getPortNumber() {
        final int DEFAULT_PORT = 80;
        ...
    }

    public String getPath() {
        final String DEFAULT_PATH = ".";
        ...
    }
    ...
}
  • 문제점
    • 기본 포트(DEFAULT_PORT)와 기본 경로(DEFAULT_PATH) 같은 설정 값이 각 함수 내부에 하드코딩되어 있음
    • 값을 변경하려면 함수를 수정해야 하므로 유지보수성이 떨어짐.
//좋은 코드

G36 : Avoid Transitive Navigation

독립성을 확보하려면 내부 상황을 서로 몰라야 한다

a.getB().getc().doSomething();
B가 마음이 바뀌어서 C가 아닌 D로 가고 싶어지면, A도 영향을 받게 되므로 문제가 된다

이것을 "Law of Demeter"라고 하며, 프로그래머는 "Writing Shy Code"라고 한다

알면 알수록 점점 강직해지는 이유는, 하나가 바뀌면 다른 것들도 다 바뀌게 되어 점점 바꾸기가 어려워지기 때문이다


G37 : Shotgun Surgery

하나의 기능이 여러 기능에 영향을 주는 경우, 하나를 바꾸면 다 수정을 해야하는 경우

언제 이런 일이 일어날까? : 중복

class SavingAccount {
	...
    void withdraw(int amount) {
    	if (this.balance < MIN_BALANCE) {
        	this.notifyAccountHolder(WITHDRAWAL_MIN_BALANCE);
        }
    }
    
    void 

만약에 withdraw 메서드에서 min_balance 뒤에 무엇을 수정한다면 나머지 메서드에서 다 수정을 해줘야 한다

if문의 조건을 함수로 뽑아낸 다음, 이것이 필요한 경우 함수를 호출해서 바꾸면 됨

수정

class SavingAccount {
	...
    void withdraw(int amount) {
    	if (isAccountUnderMinimum()) {
        	this.notifyAccountHolder(WITHDRAWAL_MIN_BALANCE);
        }
    }
    
    void transfer(int amount) {
    	if (isAccountUnderMinimum()) {
        	this.notifyAccountHolder(TRANSFER_MIN_BALANCE);
        }
    }
    
    void processFees(int fee) {
    	this.balance = this.balance - fee;
    	if (isAccountUnderMinimum()) {
        	this.notifyAccountHolder(MIN_BALANCE_WARNING);
        }
    }
    
    boolean isAccountUnderMinimum() {
    	return this.balance < MIN_BALANCE;
    }
}

하나만 수정하면 되고 나머지 세개 메서드는 그대로 두어도 괜찮아짐!


profile
욕심 많은 공대생

0개의 댓글