리팩토링

Yudrey·2022년 4월 28일
0

패스트캠퍼스 강의를 정리한 내용입니다.
"The RED : 프론트엔드 Back to the Basics : 지속 가능한 코드작성과 성능 향상법 by 김태곤"

리팩토링이란?

"소프트웨어의 겉보기 동작은 그대로 유지한 채, 코드를 이해하고 수정하기 쉽도록 내부 구조를 변경하는 기법" -마틴 파울러, 리팩터링 2판, 한빛미디어


리팩토링은 언제할까?

"3의 법칙" -돈 로버츠
1. 처음에는 그냥 한다.
2. 비슷한 일을 두 번째로 한다면 그래도 일단은 그냥 진행한다.
3. 비슷한 일을 세 번째 하면 리팩터링한다.

리팩터링 대상

나쁜 코드에서는 악취가 난다고 하고 이를 Code Smell이라고 부르며 이는 켄트 백과 마틴 파울러가 90년대 사용해서 유명해진 용어

Code Smell이 나타나는 경우

  • 너무 큰 함수나 클래스
  • 이름이 명확하지 않은 함수나 변수 이름
    → 함수나 변수 이름은 지나치게 짧은 것보다는 명확한 의미를 줄 수 있도록 조금 긴 게 나음
    → 개인 프로젝트거나 구성원 간 협의만 있으면 차라리 한국어로 작성하는 것도 좋은 방법 (어차피 bundler와 minifier가 다른 이름으로 바꿔줌)
  • 중복 코드(같은 일을 하는 코드가 여기저기 있을 때)
  • 전역 변수
    → 가능하면 함수 혹은 모듈 내에 변수 작성하는 것이 좋음
  • 과도한 콜백과 중첩된 조건문
  • 과도하게 긴 식별자

테스트 케이스 작성

  • 리팩토링 하기 전에 테스트 케이스부터 작성하기
  • 해피 패스, 노룩 리팩토링 지양하기
  • 리팩토링 시 테스트 필수

리팩토링 방법

1. 함수 추출 혹은 옯기기: 로직을 별도의 함수나 모듈로 분리

<script>
function processPosts() {
    const posts = getPosts();
    ...
    posts.forEach(post => {
        console.log(post);
    });
    ...
}

to

function logPosts(posts) {
    posts.forEach(post => {
        console.log(post);
    });
}

function processPosts() {
    const posts = getPosts();
    ...
    logPosts(posts);
    ...
}
</script>

2. 중간 변수 도입: 어떤 값인지 설명하는 중간 변수 도입

<script>
const user = getUser();
if (user.authKey) {
    ...
}

to

const user = getUser();
const isLoggedIn = Boolean(user.authKey);

if (isLoggedIn) {
    ...
}
</script>

아래와 같이 조금 복잡한 계산이 필요하다면 함수로 만드는 방법도 있음

<script>
const user = getUser();
const purchases = getPurchaseHistory(user);

// 지금까지 구매 내역이 없는 한국어 사용자에게 이벤트 배너 표시
if (user.authKey && user.locale === 'kr' && purchases.length === 0) {
    showEventBanner();
}

to

function isEligibleForEvent(user) {
    const purchases = getPurchaseHistory(user);
    const isLoggedIn = Boolean(user.authKey);
    const isKoreanUser = user.locale === 'kr';
    const hasPurchaseHistory = purchases.length > 0;

    return ( isLoggedIn && isKoreanUser && ! hasPurchaseHistory );
}


const user = getUser();
if (isEligibleForEvent(user)) {
    showEventBanner();
}
</script>

3. var가 보이거든 let, const로 변환. let 보다는 const 위주로 사용. let이 보인다면 꼭 필요한 것인지 다시 한 번 고려

4. 함수의 사이드 이펙트 최소화. 가능하면 순수 함수로 작성
순수함수란?
똑같은 입력값이 주어졌을 때 똑같은 출력을 하는 함수

*순수함수로 작성하면 함수의 역할이 명확해지고 테스트하기 편리해지므로 보다 명확하고 분명한 코드를 작성할 수 있음

5. 반복문 보다는 파이프: 이해하기 쉬움

<script>
const names = [];
for (const i of input) {
    if (i.job === 'programmer') {
        names.push(i.name);
    }
}

const names = input.filter(i => i.jpb === 'programmer').map(i => i.name);

// 비슷한 사례
const items = [1, 2, 3];
for (let i = 0; i < items.length; i++) {
    let item = items[i];
    console.log(item);
}

[1, 2, 3].forEach( item => {
    console.log(item);
} );
</script>

6. 조건, 반복문에 중괄호는 되도록이면 사용하는 것이 가독성에 좋음. 단, 한 줄에 표현할 정도로 짧고 명확하면 생략하기도 함

7. switch 대신 object literal

<script>
funtion 직업을말해봐(job) {
	switch(job) {
    	case 'engineer':
        	console.log('엔지니어');
            break;
    	case 'developer':
        	console.log('개발자');
            break;
    	case 'designer':
        	console.log('디자이너');
            break;
    }
}

to

funtion 직업을말해봐(job) {
	const translated = {
    	engineer: '엔지니어',
        developer: '개발자',
        designer: '디자이너',
    };
    console.log(translated[job]);
}
</script>

8. 배열이나 객체는 불변 객체처럼 Immutable하게 다루기 (변화가 추적되지 않아서 문제가 많이 생기는 부분이므로)

<script>
const blackPink = [ '지수', '제니', '로제', '리사' ];
blackPink.forEach((value, index) => {
    blackPink[index] += '❤️';
});
console.log(blackPink);

to 

const blackPink = [ '지수', '제니', '로제', '리사' ];
const blackPinkWithLove = blackPink.map((value, index) => {
    blackPink[index] += '❤️';
});
console.log(blackPinkWithLove);
</script>

9. 문자열 합치기 보다는 ES6 템플릿 문자열

<script>
const firstName = 'Yu';
const lastName = 'Drey';
const fullName = 'Name: ' + firstName + ' ' + lastName;

to

const fullName = `Name: + ${firstName} ${lastName}`;
</script>
profile
Frontend Developer

0개의 댓글