↔️ 문장을 함수로 옮기기
리팩터링 전
emitPhotoData(outStream, person.photo);
function emitPhotoData(outStream, photo){
outStream.write(photo.title);
outStream.write(photo.location);
}
리팩터링 후
emitPhotoData(outStream, person.photo);
outStream.write(photo.location);
function emitPhotoData(outStream, photo){
outStream.write(photo.title);
}
🧷 배경
함수는 프로그래머가 만드는 추상화 블록이다. 하지만 추상화의 경계를 올바르게 긋기가 어렵다. 함수 관점에서 생각해보면, 초기에는 응집도 높고 한 가지 일만 수행하던 함수가 어느새 둘 이상의 다른 일을 수행하게 바뀔 수도 있다.
여러 곳에서 사용하던 기능이 일부 호출자에게 다르게 동작하도록 바뀌어야 할 때 발생한다. 이때, 문장을 호출한 곳으로 옮기기 리팩터링을 적용하면 달라지는 동작을 호출자로 옮긴 뒤에 필요할 때마다 독립적으로 수정할 수 있다.
🧷 절차
1. 호출자가 한두 개 뿐이고 피호출 함수도 간단한 상황이라면, 피호출 함수의 처음( 혹은 마지막) 줄을 잘라내어 호출자로 복사해 넣는다.
2. 더 복잡한 상황에서는, 이동하지 않길 원하는 모든 문장을 함수로 추출한 다음 검색하기 쉬운 임시 이름을 지어준다.
3. 원래 함수를 인라인 한다.
4. 추출된 함수의 이름을 원래 함수의 이름으로 변경한다.
🧷 예시
function renderPerson(outStream, person) {
outStream.write(`<p>${person.name}</p>\n`);
renderPhoto(outStream, persons.photo);
emitPhotoData(outStream, person.photo);
}
function listRecentPhotos(outStream, photos) {
photos
.filter(p => p.data > recentDateCutoff())
.forEach(p => {
outStream.write("<div>\n"
emitPhotoData(outStream, p);
outStream.write("/</div>\n");
});
}
function emitPhotoData(outStream, photo) {
outStream.write(`<p>제목: ${photo.title}</p>`);
outStream.write(`<p>날짜: ${photo.date.toDateString()}</p>`);
outStream.write(`<p>위치: ${photo.location}</p>`);
}
📍 renderPerson()
은 그대로 둔 채 listRecentPhotos()
가 위치 정보를 다르게 렌더링 하도록 만들어보자.
단순한 상황에서는 renderPerson()
의 마지막 줄을 잘라내어 두 호출 코드 아래에 붙여넣으면 끝이다. 까다로운 방법으로 해보자.
emitPhotoData()
에 남길 코드를 함수로 추출한다.
function renderPerson(outStream, person) {
outStream.write(`<p>${person.name}</p>\n`);
renderPhoto(outStream, persons.photo);
emitPhotoData(outStream, person.photo);
}
function listRecentPhotos(outStream, photos) {
photos
.filter(p => p.data > recentDateCutoff())
.forEach(p => {
outStream.write("<div>\n"
emitPhotoData(outStream, p);
outStream.write("/</div>\n");
});
}
function emitPhotoData(outStream, photo) {
// 함수 추출
zztmp(outStream, photo);
outStream.write(`<p>위치: ${photo.location}</p>`);
}
function zztmp(outStream, photo) {
// 바뀌지 않을 코드
outStream.write(`<p>제목: ${photo.title}</p>`);
outStream.write(`<p>날짜: ${photo.date.toDateString()}</p>`);
}
function renderPerson(outStream, person) {
outStream.write(`<p>${person.name}</p>\n`);
renderPhoto(outStream, persons.photo);
// 분리하기
zztmp(outStream, person.photo);
outStream.write(`<p>위치: ${photo.location}</p>`); // 첫번째 호출 위치로 인라인
}
function listRecentPhotos(outStream, photos) {
photos
.filter(p => p.data > recentDateCutoff())
.forEach(p => {
outStream.write("<div>\n");
// 분리하기
zztmp(outStream, p);
outStream.write(`<p>위치: ${photo.location}</p>`); // 두번째 호출 위치로 인라인
outStream.write("/</div>\n");
});
}
function emitPhotoData(outStream, photo) {
// 함수 추출
zztmp(outStream, photo);
outStream.write(`<p>위치: ${photo.location}</p>`);
}
function zztmp(outStream, photo) {
// 바뀌지 않을 코드
outStream.write(`<p>제목: ${photo.title}</p>`);
outStream.write(`<p>날짜: ${photo.date.toDateString()}</p>`);
}
원래 함수를 지우고, zztmp()
이름을 원래 함수의 이름으로 되돌린다.
function renderPerson(outStream, person) {
outStream.write(`<p>${person.name}</p>\n`);
renderPhoto(outStream, persons.photo);
emitPhotoData(outStream, person.photo);
outStream.write(`<p>위치: ${photo.location}</p>`);
}
function listRecentPhotos(outStream, photos) {
photos
.filter(p => p.data > recentDateCutoff())
.forEach(p => {
outStream.write("<div>\n");
emitPhotoData(outStream, p);
outStream.write(`<p>위치: ${photo.location}</p>`);
outStream.write("/</div>\n");
});
}
function emitPhotoData(outStream, photo) {
outStream.write(`<p>제목: ${photo.title}</p>`);
outStream.write(`<p>날짜: ${photo.date.toDateString()}</p>`);
}
Last updated