일상/레벨업 독서

[내 코드가 그렇게 이상한가요?] 2장 설계 첫걸음

Gamii 2024. 7. 1. 22:10
728x90

 

 

1. 의도를 분명히 전달할 수 있는 이름 설계하기

 

 

문제) 어떤 일을 하는지 히해하기 힘든 로직

int d = 0;
d = p1 + p2;
d = d - ((d1 + d2) / 2);
if(d < 0){
	d = 0;
}

 

 

 

 

해결) 의도를 알 수 있는 이름 붙이기

int damageAmount = 0;
damageAmount = playerArmPower + playerWeeaponPower;
damageAmount = damageAmount - ((enemyBodyDefence + enemyArmorDefence) / 2);
if(damageAmount < 0){
	damageAmount = 0;
}

 

 

 

변수 명을 짧게 줄이면 다른 사람이 읽거나 시간이 지난 후 다시 볼 떄는 일고 이해하기가 매우 어렵습니다. 의도를 쉽게 알 수 있는 이름을 붙이세요.

 

 

 

 

 

 

 

2. 목적별로 변수를 따로 만들어서 사용하기

 

 

문제)

//1) 플레이어 공격력의 총합
damageAmount = playerArmPower + playerWeeaponPower;

//2) 적 방어력의 총합을 계산하는 부분 포함
damageAmount = damageAmount - ((enemyBodyDefence + enemyArmorDefence) / 2);

 

 

위 코드에서 대미지 크기를 나타내는 damageAmount에 값이 여러 번 할당되고 있습니다. 변수에 값을 다시 할당하는 것을 재할당이라고 합니다. 재할당은 변수의 용도가 바뀌는 문제를 일으키기 쉽습니다. 

 

 

 

 

 

해결)

int totalPlayerAttackPower = playerArmPower + playerWeaponPower;
int totalEnemeyDefence = enemyBodyDefence + enemyArmorDefence;

int damageAmount = totalPlayerAttackPower - (totalEnemeyDefence / 2);
if(damageAmount < 0){
	damageAmount = 0;
}

 

 

재할당으로 기존 변수를 다시 사용하지 말고, 목적별로 변수를 만들어서 사용합시다.

 

 

 

 

 

3. 단순 나열이 아니라, 의미 있는 것을 모아 메서드로 만들기

 

문제)

계산 로직들이 단순하게 나열되어 있으면, 로직이 어디에서 시작해서 어디에서 끝나는지, 무슨 일을 하는지 알기 어렵습니다.

(위 코드들에서 공격력과 방어력을 계산하고, 계산 결과를 다른 변수에 저장하게 만들었습니다.)

 

 

 

해결) 

의미 있는 로직을 모아서 메서드(함수)로 구현하는 것이 좋습니다.

아래 코드는 공격력 계산, 방어력 계산, 대미지 계산 코드를 메서드로 추출한 코드입니다.

 

//플레이어의 공격력 합계 계산
int sumUpPlayerAttackPower(int playerArmPower, int playerWeaponPower){
	return playerArmPower + playerWeaponPower;
}

//적의 방어력 합계 계산
int sumUpEnemyDefence(int enemyBodyDefence, int enemyArmorDefence){
	return enemyBodyDefence + enemyArmorDefence;
}

//대미지 평가
int estimateDamage(int totalPlayerAttackPower, int totalEnemyDefence){
	int damageAmount = totalPlayerAttackPower - (totalEnemyDefence / 2);
    if(damageAmount < 0){
    	damageAmount = 0;
    }
    
    return damageAmount;
}
//메서드를 호출하는 형태로 개선
int totalPlayerAttackPower 
	= sumUpPlayerAttackPower(playerBodyPower, playerWeaponPower);
    
int totalEnemyDefence 
	= sumUpEnemyDefence(enemyBodyDefence, EnemyArmorDefence);
    
int damageAmount = estimateDamage(totalPlayerAttackPower, totalEnemyDefence);

 

 

코드의 양은 많아졌지만, 메서드 별로 쉽게 역할을 구분할 수 있고 읽고 이해하기 쉬워졌습니다.

 

 

 

 

 

 

4. 관련된 데이터와 로직을 클래스로 모으기

 

 

 

 

문제) '변수'와 '변수를 조작하는 로직'이 계속해서 이곳저곳에 만들어 지고 있습니다.

 

 

그러면 관련된 로직을 찾아 돌아다니는 시간이 소모되고, 또 hitPoint에 음수 값이 포함된다든지 잘못된 값이 뒤섞여 들어갈 수도 있습니다.

 

//주인공 체력 HP
//지역 변수로 선언
int hitPoint;
//어딘가에 구현되어 있는 히트포인트 감소 로직
hitPoint = hitPoint - damageAmount;
if(hitPoint < 0){
	hitPoint = 0;
}
//어딘가에 구현되어 있는 회복 로직
hitPoint = hitPoint + recoveryAmount;
if(999 < hitPoint){
	hitPoint = 999;
}

 

 

 

 

 

해결) 클래스를 활용하면 밀접한 관계를 갖고 있는 데이터와 로직을 묶을 수 있습니다.

 

 

HitPoint 클래스에는 히트포인트와 관련된 로직을 담고 있습니다. 서로 밀접한 데이터와 로직을 한곳에 모아 두면, 이곳저곳 찾아 다니지 않아도 괜찮습니다.

 

 

//히트포인트(HP)를 나타내는 클래스
class HitPoint{
	private static final int MIN = 0;
    private static final int MAX = 999;
    final int value;
    
    HitPoint(final int value){
    	if(value < MIN){
        	throw new IllegalArgumentException(MIN + " 이상을 지정해 주세요.");
        }
        
        if(MAX < value){
        	throw new IllegalArgumentException(MAX + " 이하을 지정해 주세요.");
        }
        
        this.value = value;
    }
    
    //데미지를 받음
    HitPoint damage(final int damageAmount){
    	final int damaged = value - damageAmount;
        final int corrected = damaged < MIN ? MIN : damaged;
        return new HitPoint(corrected);
    }
    
    //회복
    HitPoint recover(final int recoveryAmount){
    	final int recovered = value + recoveryAmount;
        final int corrected = MAX < recovered? MAX : recovered;
        return new HitPoint(corrected);
    }
}