2. 하드코딩
• 데미지 계산의 예
• 데미지 = 공격력 – 방어력 * 0.5
• 위 0.5는 기획자가 임의로 정한 방어력 보정치
• 이상적인 경우
• 게임 설정 데이터에서 값을 읽어오게 하여 기획자가 바꿔가며 테스트
할 수 있도록 함
3. 하드코딩
• 0.5의 성질을 다시 생각해보자.
• 기획자가 자주 바꿀 값인가?
• 자주 사용되는 값인가?
• 데이터 관리자로부터 값을 가져오게 될텐데, 부하 문제는 없는가?
• 저 숫자 하나를 가져오기 위해 전용 데이터 관리자를 만들어야 하나?
4. 하드코딩
• 함수에 0.5를 박아넣자!
• 대대적인 개편이 아니면 데미지 공식은 자주 안바뀜
• 자주 사용되는 기능임
• 당장 빨리 개발해야함 <- 제일 중요!!
func CaluclateDamage(attack, defense)
{
return attack – defense * 0.5;
}
5. 하드코딩을 하는 건 좋은데…
• 한달 후 다른 개발자가 데미지 계산 함수를 보았을 때
• 0.5의 의미가 뭘까? 절반으로 만들기 위한 건가?
• 그래서 기획자에게 물어보고 아래와 같이 주석을 추가했다.
• 데미지 공식이 개편되면 저 주석도 바꿔줘야 함
func CaluclateDamage(attack, defense)
{
// 0.5는 방어력 보정치
return attack – defense * 0.5;
}
6. 하드코딩을 하는 건 좋은데…
• 하드코딩하려 했던 대상을 다시 생각해보자.
• 데미지 = 공격력 – 방어력 * 0.5
• 데미지 = 공격력 – 방어력 * 방어력 보정치
• 0.5를 하드코딩하는게 아니라 “방어력 보정치” 를 하드코딩 해
야 한다.
• 매우 중요!!
7. 상수
• 프로그램 자체에 박힌 값으로 실행 중에 바뀌지 않는다.
func CaluclateDamage(attack, defense)
{
// 0.5는 방어력 보정치
return attack – defense * 0.5;
}
const var defenseAdjust = 0.5;
func CaluclateDamage(attack, defense)
{
return attack – defense * defenseAdjust;
}
8. 네이밍
• 코드에서 표현하고자 하는 대상에 이름을 붙여주는 것
• 앞의 예에서 적절한 네이밍을 통해 얻을 수 있는 장점은 어떤
것이 있었을까?
9. 네이밍
• 주석 없이 코드 자체만으로 내용을 이해할 수 있다.
• “공격력 – 방어력 * 방어력 보정치” 라는 자연어에 가까운 코드가 됨
• 다른 코드에서도 같은 값을 사용하고 있을 때 한꺼번에 수정하
기 쉬움
• 이건 위 장점을 달성하면서 부차적으로 얻을 수 있는 효과라고 생각함
func CaluclateDamage(attack, defense)
{
// 0.5는 방어력 보정치
return attack – defense * 0.5;
}
const var defenseAdjust = 0.5;
func CaluclateDamage(attack, defense)
{
return attack – defense * defenseAdjust;
}
10. 잘못된 네이밍의 예
• 1001 버프가 걸리면 1002, 1003 버
프가 함께 걸리는 하드코딩
• 코드만 봐서는 어떤 동작이 일어나
는지는 알 수 있지만 왜 이런 코드
가 들어갔는지는 알 수 없다.
var sniperBuff1ID = 1001;
var sniperBuff2ID = 1002;
var sniperBuff3ID = 1003;
func OnBuffApplied(buff)
{
if (buff.ID == sniperBuff1ID)
{
ApplyBuff(sniperBuff2ID);
ApplyBuff(sniperBuff3ID);
}
}
11. 잘못된 네이밍의 예
• 스나이퍼 모드가 되면 공격
력은 높아지지만 속도는 느
려지는 기획이었음
• 네이밍 수정만으로 주석이
필요없는 코드가 됨
• 거듭 강조!
• 하드코딩하려 했던 것은 1001
이라는 숫자가 아니라 “스나이
핑 모드 버프”
var sniperModeBuffID = 1001;
var sniperAttackBuffID = 1002;
var sniperSlowBuffID = 1003;
func OnBuffApplied(buff)
{
if (buff.ID == sniperModeBuffID)
{
ApplyBuff(sniperAttackBuffID);
ApplyBuff(sniperSlowBuffID);
}
}
12. 매우 긴 함수
• 플레이어가 맵에 입장했을 때
현재 맵 상태를 인코딩하는
함수
• 맵의 구성요소가 많을수록 함
수가 길어진다.
func EncodeMap()
{
// 맵 기본정보 인코딩
기상정보 인코딩
재생중인 배경음악 인코딩
// 모든 플레이어 인코딩
for (i = 0; i <= players.count; ++i)
{
i번째 플레이어 인코딩
}
// 드랍되어있는 아이템 인코딩
…
}
13. 매우 긴 함수 – 코드 블록에 네이밍
• 주석을 기준으로 코드
블록을 함수로 묶어냄
• 함수의 전체 흐름을 알
아보기 쉬워짐
• 자연어 문단 읽듯이 읽
을 수 있음
func EncodeMap()
{
EncodeMapInfo();
EncodePlayers();
EncodeDroppedItems();
} func EncodePlayers()
{
for (i = 0; i <= players.count; ++i)
{
i번째 플레이어 인코딩
}
}
func EncodeMapInfo()
{
기상정보 인코딩
재생중인 배경음악 인코딩
}
func EncodeDroppedItems()
{
…
}
14. 매우 긴 라인
func UpdateChargeStack()
{
if ((현재카운트 < 최대카운트) and (현재 시간 >= 마지막 충전 시간 + 충전 주기))
{
카운트++;
마지막 충전 시간 = 현재 시간;
}
}
15. 매우 긴 라인 – 논리 단위에 네이밍
• 거듭 강조하듯, 자연어 읽듯이 코드를 읽을 수 있음
• 논리 단위로 테스트하기 용이함
func UpdateChargeStack()
{
if ((not IsMaxStacked()) and IsChargeInvervalOvered())
{
카운트++;
마지막 충전 시간 = 현재 시간;
}
}
16. 요약
• 대상을 정확히 표현할 수 있는 네이밍 사용
• 주석은 네이밍의 기준이 될 수 있다.
• 주석을 줄이려고 노력하면 명확한 코드 짜기에 도움이 된다.
• 주석에 너무 의존하면 함정 주석에 발목 잡힐 수 있음
• 논리 단위로 뽑아낼 수 있는 코드는 네이밍을 붙여 분리