리팩토링 이란 코드가 하는 일을 변경하지 않고 더 나은 코드를 만드는 것이라고 1장에서 정의했었는데 2장에서는 더 나은 코드를 만드는 것과 코드가 하는 일을 변경하지 않는다 이 2가지 내용이 나왔는데 더 나은 코드가 되기 위해선 가독성과 유지 보수성이 뛰어나야 한다는 내용이었다.
책에서 가독성이란 의도를 전달하기 위한 코드의 성질이라고 정의가 되어있는데 이 말은 곧 코드가 무슨 일을 하는지 파악하기 매우 쉽고 가독성을 향상시키기 위한 방법으로는 코딩 컨벤션, 주석, 변수, 메서드, 클래스 및 파일 이름 지정 등 여러 가지 방법을 나열해 주지만 변수, 메서드 이런 변수명 짓는 이름은 딱 정답이라는 게 없는 거 같아서 어려운 거 같다.
유지 보수성의 정의로는 얼마나 많은 후보를 조사해야 하는지를 나타내는 표현이라고 되어있었는데 처음 딱 읽었을 때는 무슨 말인지 와닿지가 않아서 좀 더 생각을 해봤다.
여기서 후보란 코드 복잡도, 중복 코드의 양, 코드 가독성 등 유지 보수를 측정하기 위한 기준과 방법을 지칭하는 것으로 사용한 거 같지만 아직도 이해가 잘 안되는 문장이긴 하다 스터디 때 공유를 해보면 좋을 거 같다.
유지 보수성을 향상시킬 수 있는 방법으로는 변수를 명시적으로 체크해서 불변 속성을 제거하는 방법이 있다고 적혀있는데 나름 해석을 하자면 불변성을 유지함으로써 유지 보수성을 향상시킬 수 있다는 의미로 보였다. 이렇게 하면 코드가 수행하는 작업이 변경된다고 했는데 이런 경우엔 불변 속성을 더욱 쉽게 볼 수 있도록 서로 가깝게 이동시켜 유지 보수성을 향상시킨다고 되어있었다. ( 불변 속성의 범위 제한 ) 이 말인즉슨 변경이 필요한 부분을 가능한 지역화한다는 표현으로 이해했다.
앞에 설명한 내용을 토대로 리팩터링의 세 가지 핵심은 이렇다.
이다음 내용으로는 안정성, 유연성을 강조하기 위해 상속보다는 컴포지션을 사용하라라는 말이 나오는데 상속은 class 간의 계층 구조가 있는 경우엔 사용되는 것이란 걸 알지만 컴포지션은 처음 본 개념이라 찾아봤는데 객체 간의 강한 결합도를 낮추고, 객체 간의 독립성을 보존하면서도 코드 재사용성을 높일 수 있다고 되어있어 얼핏 봤을 땐 이해가 잘되지 않아. chatgpt를 통해 javascript 코드로 보니 이해에 도움됬다.
// 동물 클래스
class Animal {
constructor(name) {
this.name = name;
}
eat() {
console.log(`${this.name} is eating.`);
}
}
// 개 클래스
class Dog extends Animal {
constructor(name, breed) {
super(name);
this.breed = breed;
}
bark() {
console.log(`${this.name} is barking.`);
}
}
// 고양이 클래스
class Cat extends Animal {
constructor(name, color) {
super(name);
this.color = color;
}
meow() {
console.log(`${this.name} is meowing.`);
}
}
// 새 클래스
class Bird extends Animal {
constructor(name, wingspan) {
super(name);
this.wingspan = wingspan;
}
fly() {
console.log(`${this.name} is flying.`);
}
}
// 자동차 클래스
class Car {
constructor(engine, wheels, windows) {
this.engine = engine;
this.wheels = wheels;
this.windows = windows;
}
start() {
this.engine.start();
this.wheels.rotate();
console.log('Car started');
}
stop() {
this.engine.stop();
console.log('Car stopped');
}
}
// 엔진 클래스
class Engine {
start() {
console.log('Engine started');
}
stop() {
console.log('Engine stopped');
}
}
// 바퀴 클래스
class Wheels {
rotate() {
console.log('Wheel rotating');
}
}
// 창문 클래스
class Windows {
open() {
console.log('Window opened');
}
close() {
console.log('Window closed');
}
}
let myDog = new Dog("Max", "Poodle");
myDog.eat(); // 출력: Max is eating.
myDog.bark(); // 출력: Max is barking.
let myCat = new Cat("Kitty", "White");
myCat.eat(); // 출력: Kitty is eating.
myCat.meow(); // 출력: Kitty is meowing.
let myBird = new Bird("Polly", 30);
myBird.eat(); // 출력: Polly is eating.
myBird.fly(); // 출력: Polly is flying.
let myEngine = new Engine();
let myWheels = new Wheels();
let myWindows = new Windows();
let myCar = new Car(myEngine, myWheels, myWindows);
myCar.start(); // 출력: Engine started, Wheel rotating, Car started
myCar.stop(); // 출력: Engine stopped, Car stopped
이렇게 컴포지션으로 만든 시스템을 사용하면 로고 블록을 가지고 노는 것과 마찬가지로 그 자리의 부품만 교체하면 되니 의존성을 낮춰 유연성을 증가시킬 수 있겠다는 생각이 들었고 컴포지션의 가장 큰 장점은 추가로 변경이 가능하다는 것이라는 부분에서 새로운 코드를 작성해서 그 부분을 교체했는데 의도치 않은 에러가 난다면 전에 쓰던 걸로 바로 교체할 수 있으니 안정성을 높여준다고 표현한 거 같다.
이번 장에서 가독성, 유지 보수성에 대한 개념은 크게 어렵지 않았고 상속과 컴포지션의 개념과 차이를 알게 된 것이 좋았다. 전에 객체지향의 사실과 오해 책을 스터디 한 후 객체지향 프로그래밍에 관심이 생겼는데 상속, 컴포지션을 적절히 사용하여 게임 같은 것을 만들어보면 좋겠다는 생각을 했다.
책을 읽을 때 지은이가 외국 사람인 경우 번역본이더라도 좀 어색하거나 어려운 표현들이 있는데 chatgpt를 통해서 설명해달라하니 생각보다 잘 설명해 준다 앞으로 잘 활용해 봐야겠다.