반응형
    
    
    
  클린코드(CleanCode)를 읽고 간략하게 정리한 글입니다.

14장. 점진적인 개선
1. 점진적인 개선의 중요성
- 지속적 개선
 - 소프트웨어는 한 번에 완벽해질 수 없다.
 - 꾸준한 점진적 개선이 필요하다.
 - 작은 변경을 자주 적용하는 방식이 대규모 변경을 한 번에 적용하는 것보다 효과적이다.
- 유지보수성 향상
 - 코드는 시간이 지남에 따라 변경되고 개선되어야 유지보수성이 높아진다.
 - 점진적인 개선은 코드를 최신 상태로 유지하는 데 중요하다.
2. 개선 방법
2-1. 리팩토링
- 정의
 - 리팩토링은 소프트웨어의 기능을 변경하지 않으면서 코드를 재구성하는 것을 의미한다.
- 목표
 - 코드를 더 읽기 쉽고 이해하기 쉽게 만들며, 중복을 제거하고, 구조를 개선한다.
- 방법
 - 작은 단위로 점진적으로 리팩토링한다.
 - 하나의 작업을 끝내고 테스트를 통과한 후에 다음 작업으로 넘어간다.
2-2. 테스트 주도 개발(TDD)
- 정의
 - 테스트를 먼저 작성하고, 그 테스트를 통과하는 코드를 작성하는 개발 방식
- 목표
 - 코드가 예상대로 동작하는지 확인하고, 리팩토링을 안전하게 수행
- 방법
 - 새로운 기능을 추가할 때마다 먼저 테스트를 작성하고, 테스트가 실패하면 코드를 작성하여 통과시킴
2-3. 작은 단위의 변경
- 정의
 - 작은 단위로 자주 변경하는 것이 큰 단위로 드물게 변경하는 것보다 낫다.
- 목표
 - 변경 사항을 쉽게 이해하고, 버그 발생 가능성을 줄이며, 문제 발생 시 원인을 쉽게 찾을 수 있게 한다.
- 방법
 - 변경할 부분을 작게 나누어, 각 변경 후에 테스트를 수행하여 코드의 안정성을 유지한다.
3. 코드 리뷰와 피드백
- 코드 리뷰
 - 코드 리뷰는 다른 개발자의 피드백을 받아 코드를 개선하는 중요한 과정이다.
 - 코드 리뷰를 통해 코드 품질을 높이고, 잠재적인 문제를 사전에 발견할 수 있다.
- 피드백 루프
 - 짧은 피드백 루프를 유지하여 빠르게 개선점을 반영한다.
 - 이는 개발 과정에서 지속적으로 학습하고 성장할 수 있게 한다.
4. 개선 문화
- 지속적 개선 문화
 - 팀 전체가 점진적 개선의 중요성을 이해하고, 이를 실천하는 문화를 조성한다.
 - 코드의 품질을 높이기 위해 누구나 개선 제안을 할 수 있는 환경을 만든다.
- 자동화
 - 빌드, 테스트, 배포 과정을 자동화하여 개발 주기를 단축하고, 반복 작업을 줄여 점진적인 개선을 촉진한다.
5. 리팩토링 예제
- 간단한 은행 계좌 클래스를 리팩토링하고 점진적으로 개선하는 과정
5-1. 초기 코드
- 먼저 기본적인 은행 계좌 클래스와 관련 메소드를 작성한다.
public class BankAccount {
    private double balance;
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
        }
    }
    public double getBalance() {
        return balance;
    }
}5-2. 테스트 코드
- TDD를 위해 은행 계좌 클래스의 동작을 검증하는 테스트 코드를 작성한다.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class BankAccountTest {
    @Test
    public void testDeposit() {
        BankAccount account = new BankAccount(100);
        account.deposit(50);
        assertEquals(150, account.getBalance());
    }
    @Test
    public void testWithdraw() {
        BankAccount account = new BankAccount(100);
        account.withdraw(50);
        assertEquals(50, account.getBalance());
    }
    @Test
    public void testWithdrawMoreThanBalance() {
        BankAccount account = new BankAccount(100);
        account.withdraw(150);
        assertEquals(100, account.getBalance());
    }
}5-3. 리팩토링 1 : 중복 코드 제거
- 입금과 출금 메소드의 검증 로직을 별도의 메소드로 추출하여 중복 코드를 제거한다.
public class BankAccount {
    private double balance;
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }
    public void deposit(double amount) {
        if (isValidAmount(amount)) {
            balance += amount;
        }
    }
    public void withdraw(double amount) {
        if (isValidAmount(amount) && amount <= balance) {
            balance -= amount;
        }
    }
    public double getBalance() {
        return balance;
    }
    // 중복 코드 메소드로 추출
    private boolean isValidAmount(double amount) {
        return amount > 0;
    }
}5-4. 리팩토링 2: 예외 처리 추가
- 입금 또는 출금 시 잘못된 금액에 대한 예외 처리를 추가한다.
public class BankAccount {
    private double balance;
    public BankAccount(double initialBalance) {
        this.balance = initialBalance;
    }
    public void deposit(double amount) {
        if (!isValidAmount(amount)) {
            // 예외 처리 추가
            throw new IllegalArgumentException("Amount must be greater than zero");
        }
        balance += amount;
    }
    public void withdraw(double amount) {
        if (!isValidAmount(amount)) {
            throw new IllegalArgumentException("Amount must be greater than zero");
        }
        if (amount > balance) {
            throw new IllegalArgumentException("Insufficient balance");
        }
        balance -= amount;
    }
    public double getBalance() {
        return balance;
    }
    private boolean isValidAmount(double amount) {
        return amount > 0;
    }
}5-5. 예외 처리 테스트 추가
- 새로운 예외 처리 로직에 대한 테스트를 추가하여 TDD 를 유지한다.
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class BankAccountTest {
    @Test
    public void testDeposit() {
        BankAccount account = new BankAccount(100);
        account.deposit(50);
        assertEquals(150, account.getBalance());
    }
    @Test
    public void testWithdraw() {
        BankAccount account = new BankAccount(100);
        account.withdraw(50);
        assertEquals(50, account.getBalance());
    }
    @Test
    public void testWithdrawMoreThanBalance() {
        BankAccount account = new BankAccount(100);
        account.withdraw(150);
        assertEquals(100, account.getBalance());
    }
    @Test
    public void testDepositNegativeAmount() {
        BankAccount account = new BankAccount(100);
        assertThrows(IllegalArgumentException.class, () -> {
            account.deposit(-50);
        });
    }
    @Test
    public void testWithdrawNegativeAmount() {
        BankAccount account = new BankAccount(100);
        assertThrows(IllegalArgumentException.class, () -> {
            account.withdraw(-50);
        });
    }
    @Test
    public void testWithdrawInsufficientBalance() {
        BankAccount account = new BankAccount(100);
        assertThrows(IllegalArgumentException.class, () -> {
            account.withdraw(150);
        });
    }
}6. 결론
- 지속적인 리팩토링
 - 점진적인 개선을 위해 지속적으로 코드를 리팩토링하고, 테스트를 통해 코드의 안정성을 확인한다.
- 작은 단위로 자주 변경
 - 큰 단위의 변경보다 작은 단위로 자주 변경하는 것이 좋다.
- 팀 협업과 피드백
 - 코드 리뷰와 피드백을 통해 코드 품질을 높이고, 지속적인 개선 문화를 조성한다.
반응형
    
    
    
  'Study > CleanCode' 카테고리의 다른 글
| [클린코드] 13장. 동시성 (0) | 2024.07.02 | 
|---|---|
| [클린코드] 7장. 오류처리 (0) | 2024.06.28 | 
| [클린코드] 12장. 창발성 (0) | 2024.06.27 | 
| [클린코드] 11장. 시스템 (0) | 2023.11.15 | 
| [클린코드] 10장. 클래스 (2) | 2023.11.12 |