리팩터링?
-> 기능을 변경하지 않고 코드의 가독성과 유지보수가 쉽도록 코드를 변경하는 것
가독성 : 의도를 전달하기 위한 코드의 성질
코드에서 의도를 전달하는 방법
- 컨벤션, 주석, 변수, 메서드, 클래스 및 파일 이름, 공백 사용 등
유지보수성 : 버그를 고치거나 기능을 추가하기 위해 코드를 수정할 후보가 얼마나 많은지 나타냄
시스템이 취약하다 = 시스템에서 A를 수정했는데 B에도 영향이 가는 경우
이때, 취약성의 근원은 일반적으로 전역상태(global state) 때문!
전역상태(global state) : 프로그램이 실행되는 동안 변경될 수 있는 모든 것. ex) 모든 변수, DB의 데이터, 하드디스크 안의 파일 등
특히, 불변속성(invariant) 변수로 인해 시스템의 취약성이 증가한다
불변속성(invariant) : assertion 또는 주석으로만 표시한 속성. ex) "이 숫자는 절대 음수일 수 없습니다", "이 파일은 확실히 존재합니다" 등
시스템이 변경되거나 새로운 개발자가 팀에 추가될 때 불변속성이 유효한 상태로 유지되기는 어렵다
불변속성을 더욱 쉽게 볼 수 있도록 서로 가깝게 이동시켜 리팩터링을 진행하는 것이 좋음
'함께 변하는 것은 함께 있어야 한다' 라는 의미의 불변속성의 범위제한(localizing invariants)
상속보다는 컴포지션(composition)을 사용
컴포지션(composition) : 객체가 내부에서 다른 객체의 참조를 가지는 것
interface Bird {
hasBeak(): boolean;
canFly(): boolean;
}
class CommonBird implements Bird {
hasBeak(): boolean {
return true;
}
canFly(): boolean {
return true;
}
}
// 상속 사용
class Penguin extends CommonBird {
canFly(): boolean {
return false;
}
}
interface Bird {
hasBeak(): boolean;
canFly(): boolean;
}
class CommonBird implements Bird {
hasBeak(): boolean {
return true;
}
canFly(): boolean {
return true;
}
}
class Penguin implements Bird {
private bird = new CommonBird(); // 컴포지션
hasBeak(): boolean {
return this.bird.hasBeak();
}
canFly(): boolean {
return false;
}
}
위에 있는 코드는 상속을 사용했고 아래에 있는 코드는 컴포지션을 사용함
Bird 인터페이스에 canSwim 메서드를 추가하면 컴포지션을 사용한 Penguin 클래스는 canSwim을 구현하지 않았으므로 컴파일 에러가 발생함
즉, 프로그래머에게 Penguin이 수영을 할 수 있는지 여부의 구현을 강제함!
위의 예시에서 알 수 있듯이 컴포지션의 장점은 코드를 수정하는 것이 아니라 코드를 추가함으로써 코드에 변경을 준다는 것
**SOLID 원칙 중 Open-Close 원칙 - 확장에는 열려 있어야 하고 수정에 대해 닫혀있어야 함**
'책 > 파이브 라인스 오브 코드' 카테고리의 다른 글
5장 - 유사한 코드 융합하기 (0) | 2024.02.17 |
---|---|
4장 - 타입 코드 처리하기 [긴 if 문 리팩터링] (0) | 2024.02.05 |
4장 - 타입 코드 처리하기 [간단한 if 문 리팩터링] (0) | 2024.02.03 |
3장 - 긴 코드 조각내기 for 메서드 다섯 줄 제한(FIVE LINES) (0) | 2024.01.31 |
1장 - 리팩터링 리팩터링하기 (0) | 2024.01.29 |