핀수로그
  • [아무튼 필사] 내 코드가 그렇게 이상한가요? 3일차
    2023년 12월 20일 18시 33분 40초에 업로드 된 글입니다.
    작성자: 핀수
    728x90
    반응형

    2장 설계 첫걸음

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

    ...
    이름을 짧게 줄이면, 입력해야 하는 글자 수가 줄어듭니다. 따라서 조금이라도 빠르게 구현할 수 있을지도 모릅니다. 하지만 이 코드를 다른 사람이 읽거나 시간이 지난 후 다시 볼 때는 읽고 이해하기 매우 어렵습니다. 입력할 때 시간보다 몇 배, 아니 몇십 배 이상이 필요할지도 모릅니다. 
    ...
    자주 바뀔 가능성이 있는 코드를 구현할 때는 '변수 이름을 쉽게 붙이는 것'도 아주 훌륭한 기본 설계가 될 수 있습니다. 의도를 쉽게 알 수 있는 이름을 붙이세요.
    ...

    2.2 목적별로 변수를 따로 만들어 사용하기

    ...
    변수에 값을 다시 할당하는 것을 재할당이라고 합니다. 재할당은 변수의 용도가 바뀌는 문제를 일으키기 쉽습니다. 그러면 코드를 읽는 사람을 혼란스럽게 만들고, 버그를 만들어 낼 가능성이 있습니다.
    ...
    재할당으로 기존의 변수를 다시 사용하지 말고, 목적별로 변수를 만들어서 사용합시다.
    ...

    2.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) {
            return 0;
        }
        return damageAmount;
    }

     
    이 메서드들을 호출하는 형태로 개선해 봅시다.

    int totalPlayerAttackPower = sumUpPlayerAttackPower(playerBodyPower, playerWeaponPower);
    int totalEnemyDefence = sumUpEnemyDefence(enemyBodyDefence, enemyArmorDefence);
    int damageAmount = estimateDamage(totalPlayerAttackPower, totalEnemyDefence);

     
    세부 계산 로직을 메서드로 감쌌으므로, 일련의 흐름이 훨씬 쉽게 읽힙니다.
    또한 서로 다른 계산 작업을 각각의 메서드로 분리했으므로 쉽게 구분할 수 있습니다.
    ...
    코드의 양은 많아졌지만, 읽고 이해하기는 훨씬 쉽습니다.
    이처럼 유지 보수와 변경이 쉽도록 변수의 이름과 로직을 신경 써서 작성하는 것이 곧 설계입니다.

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

    ...
    '변수'와 '변수를 조작하는 로직'이 계속해서 이곳저곳에 만들어지고 있습니다. 이런 현상은 게임에서만 일어나는 일이 아닙니다. 작은 프로그램에서는 큰 문제 없겠지만 수천, 수만 줄의 소스 코드로 이루어진 프로그램이라면, 관련된 로직을 찾아 돌아다니는 시간만 따져도 엄청날 것입니다.
    ...
    값이 잘못된 상태로 프로그램이 계속해서 동작한다면, 버그가 발생할 것입니다.
    이러한 문제를 해결해 주는 것이 바로 클래스입니다. 클래스는 데이터를 인스턴스 변수로 갖고, 인스턴스 변수를 조작하는 메서드를 통해 함께 모아 놓은 것입니다.

    public class HitPoint {
        private static final int MIN = 0;
        public 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);
        }
    }

     
    ...
    서로 밀접한 데이터와 로직을 한곳에 모아 두면, 이곳저곳 찾아 다니지 않아도 괜찮습니다. 
    그리고 생성자에는 0~999 범위를 벗어나는 값을 거부하는 로직이 있습니다. 
    잘못된 값이 유입되지 않게 만들면, 조금이나마 버그로부터 안전한 클래스 구조가 될 것입니다.
    이처럼 의도를 갖고 적절하게 설계하면, 유지 보수와 변경이 쉬워집니다.


    이번 시간에는 설계를 위한 첫걸음인 클래스를 작성하는 방법에 대해 알아보았다.
    (여기서 방법은 코드 상의 방법을 이야기 하는 것이 아님)
    큰 줄기로만 본다면 ’개발할 때 당연한 것들 아냐?‘라고 생각할 수 있겠지만 시간과 업무에 치이다 보면 가끔 이 당연한 것들을 빠트리기도 한다.
    그래서 이것들을 계속해서 되새기는 것이다.

     

    필사할 것을 찾기 위해 책을 계속 읽어보고 있는데 이것도 꽤나 공부가 되는 것 같다 ㅎㅎ

    내일은 어떤 것을 깨닫고 반성하게 될까..큭큭

    우리 존재 화이팅


    출처

     

    내 코드가 그렇게 이상한가요?

    공감 100% 나쁜 코드 사례로 배우는 지속 가능한 코드 설계 입문서. 객체 지향 설계를 통해 코드 품질을 높이는 방법을 설명한다. 설계를 고민하지 않고 작성한 코드는 오로지 한 치 앞만 바라본

    www.aladin.co.kr

     

    728x90
    반응형
    댓글