Study/CleanCode
[클린코드] 14장. 점진적인 개선
Wonol
2024. 7. 4. 08:25
반응형
클린코드(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. 결론
- 지속적인 리팩토링
- 점진적인 개선을 위해 지속적으로 코드를 리팩토링하고, 테스트를 통해 코드의 안정성을 확인한다. - 작은 단위로 자주 변경
- 큰 단위의 변경보다 작은 단위로 자주 변경하는 것이 좋다. - 팀 협업과 피드백
- 코드 리뷰와 피드백을 통해 코드 품질을 높이고, 지속적인 개선 문화를 조성한다.
반응형