당신을 데리고 전방 공사(10): 재구성

9079 단어 javascript 전단
《재구성2》라는 책에서 재구성에 대해 정의를 내렸다.
이른바 재구성(refactoring)은 이러한 과정이다. 코드의 외적 행위를 바꾸지 않는 전제에서 코드를 수정하여 프로그램의 내부 구조를 개선한다.재구성은 여러 가지 단련을 거쳐 형성된 질서정연한 절차 정리 방법으로 정리 과정에서 오류가 도입될 확률을 최대한 줄일 수 있다.본질적으로 재구성은 코드를 다 쓴 후에 디자인을 개선하는 것이다.
재구성과 성능 최적화는 공통점도 있고 차이점도 있다.
같은 점은 프로그램 기능을 바꾸지 않고 코드를 수정하는 것이다.다른 점은 재구성은 코드를 더욱 쉽게 이해하고 수정하기 위한 것이고 성능 최적화는 프로그램을 더욱 빨리 실행하기 위한 것이다.여기서 한 가지 더 중점적으로 말하자면, 측면의 중점이 다르기 때문에 재구성은 프로그램을 더욱 빨리 실행할 수도 있고, 프로그램을 더욱 느리게 실행할 수도 있다.
재구성은 코드를 쓰면서 재구성할 수도 있고, 프로그램을 다 쓴 후에 일정 시간 동안 전문적으로 재구성할 수도 있다.어떤 방식이 더 좋은지는 말하지 않고 개인의 상황을 보고 결정한다.만약 당신이 전문적으로 시간을 가지고 재구성을 한다면, 코드를 재구성한 후 즉시 테스트를 진행하는 것을 권장합니다.이렇게 하면 코드를 너무 많이 수정해서 오류가 발생할 때 오류점을 찾을 수 없다는 것을 피할 수 있다.
재구성의 원칙
  • 세 가지를 넘지 않고 세 가지를 재구성한다.같은 코드를 반복해서 쓸 수 없는 상황에서 재구성해야 한다는 것이다.
  • 코드 한 토막이 이해하기 어려우면 재구성을 고려해야 한다.
  • 코드를 이해했지만 매우 번거롭거나 부족하면 재구성할 수 있다.
  • 너무 긴 함수, 재구성이 필요합니다.
  • 한 함수는 한 기능에 대응하는 것이 가장 좋다. 만약 한 함수가 여러 기능에 삽입된다면 그것을 재구성해야 한다.(4 및 5 충돌 없음)
  • 재구성의 관건은 대량의 미소하고 소프트웨어 행위를 유지하는 절차를 활용하여 한 걸음 한 걸음 대규모의 수정을 달성하는 데 있다.모든 단독의 재구성은 아주 작거나 약간의 작은 절차로 조합되어 있다.

  • 재구성법
    《재구성2》 이 책에는 수백 가지에 달하는 재구성 기법이 소개되어 있다.그러나 나는 다음과 같은 8가지가 비교적 자주 사용된다고 생각한다.
  • 중복 코드를 추출하여 함수로 봉함
  • 분해 기능이 너무 많은 함수
  • 변수/함수 개명
  • 대체 알고리즘
  • 내연 코드 대신 함수 호출
  • 이동문
  • 플러그 조건 표현식
  • 조회 함수와 수정 함수를 분리
  • 중복 코드를 추출하여 함수로 봉인하다
    검색 데이터의 인터페이스가 있다고 가정하십시오. /getUserData?age=17&city=beijing현재 필요한 것은 사용자 데이터: { age: 17, city: 'beijing' } 를 URL 매개 변수로 바꾸는 것입니다.
    let result = ''
    const keys = Object.keys(data)  // { age: 17, city: 'beijing' }
    keys.forEach(key => {
        result += '&' + key + '=' + data[key]
    })
    
    result.substr(1) // age=17&city=beijing

    만약 이 인터페이스만 변환이 필요하다면 함수로 봉하지 않는 것은 문제없다.그러나 여러 인터페이스에 이런 수요가 있다면 그것을 함수로 봉해야 한다.
    function JSON2Params(data) {
        let result = ''
        const keys = Object.keys(data)
        keys.forEach(key => {
            result += '&' + key + '=' + data[key]
        })
    
        return result.substr(1)
    }

    너무 많은 함수 분할
    다음은 청구서를 인쇄하는 프로그램입니다.
    function printBill(data = []) {
        //     
        const total = {}
        data.forEach(item => {
            if (total[item.department] === undefined) {
                total[item.department] = 0
            }
    
            total[item.department] += item.value
        })
        //         
        const keys = Object.keys(total)
        keys.forEach(key => {
            console.log(`${key}   :${total[key]}`)
        })
    }
    
    printBill([
        {
            department: '   ',
            value: 89,
        },
        {
            department: '   ',
            value: 132,
        },
        {
            department: '   ',
            value: 78,
        },
        {
            department: '   ',
            value: 90,
        },
        {
            department: '   ',
            value: 56,
        },
        {
            department: '   ',
            value: 120,
        },
    ])

    printBill() 함수는 실제적으로 두 가지 기능을 포함하는데 그것이 바로 집합과 인쇄이다.우리는 전체 데이터의 코드를 추출하여 하나의 함수로 봉인할 수 있다.이렇게 하면 printBill() 함수는 인쇄 기능에만 관심을 기울일 수 있다.
    function printBill(data = []) {
        const total = calculateBillData(data)
        const keys = Object.keys(total)
        keys.forEach(key => {
            console.log(`${key}   :${total[key]}`)
        })
    }
    
    function calculateBillData(data) {
        const total = {}
        data.forEach(item => {
            if (total[item.department] === undefined) {
                total[item.department] = 0
            }
    
            total[item.department] += item.value
        })
    
        return total
    }

    변수/함수 개명
    변수 이름이든 함수 이름이든 간에 가능한 한 다른 사람이 당신의 변수/함수가 무엇을 하는지 알게 해야 합니다.변수 명칭의 규칙은'무엇인가'에 중점을 두고 함수 명칭의 규칙은'무엇을 하는가'에 중점을 두고 있다.
    변량
    const a = width * height

    위의 이 변수는 그다지 좋지 않아서 a 그것이 무엇인지 알아보기 어렵다.
    const area = width * height

    이렇게 바꾸면 이해하기 쉽다. 원래 이 변수는 면적을 표시하는 것이다.
    함수.
    function cache(data) {
        const result = []
        data.forEach(item => {
            if (item.isCache) {
                result.push(item)
            }
        })
    
        return result
    }

    이 함수 명칭은 사람을 매우 의심하게 할 것이다. cache는 무엇을 대표하는가?캐시를 설정하시겠습니까, 제거하시겠습니까?코드를 다시 자세히 보니, 아, 캐시 데이터를 얻었구나.그래서 이 함수의 명칭을 getCache()로 바꾸는 것이 더욱 적합하다.
    대체 알고리즘
    function foundPersonData(person) {
        if (person == 'Tom') {
            return {
                name: 'Tom',
                age: 18,
                id: 21,
            }
        }
    
        if (person == 'Jim') {
            return {
                name: 'Jim',
                age: 20,
                id: 111,
            }
        }
    
        if (person == 'Lin') {
            return {
                name: 'Lin',
                age: 19,
                id: 10,
            }
        }
    
        return null
    }

    위의 이 함수의 기능은 사용자 이름에 따라 사용자의 상세한 정보를 찾는 것이다. 이 함수는 세 번if 판단을 했고 데이터를 찾지 못하면 되돌아온다null.이 함수는 확장에 불리합니다. 사용자마다 if 문장을 많이 써야 합니다. 우리는 더욱 편리한 '찾기표' 로 바꿀 수 있습니다.
    function foundPersonData(person) {
        const data = {
            'Tom': {
                name: 'Tom',
                age: 18,
                id: 21,
            },
            'Jim': {
                name: 'Jim',
                age: 20,
                id: 111,
            },
            'Lin': {
                name: 'Lin',
                age: 19,
                id: 10,
            },
        }
    
        return data[person] || null
    }

    수정 후 코드 구조가 더욱 뚜렷해 보이고 미래에 확장하기에도 편리하다.
    함수 호출로 내연 코드를 대체하다
    만약 일부 코드가 한 일이 기존 함수의 기능과 중복된다면, 이 코드들을 함수 호출로 대체하는 것이 가장 좋다.
    let hasApple = false
    for (const fruit of fruits) {
        if (fruit == 'apple') {
            hasApple = true
            break
        }
    }

    예를 들어 위의 코드는 배열includes() 방법으로 대체할 수 있습니다.
    const hasApple = fruits.includes('apple')

    수정 후 코드가 더욱 간결하다.
    이동 문
    관련된 것이 함께 나타나게 하면 코드를 더욱 쉽게 이해할 수 있다.만약 일부 코드가 한 곳에 작용한다면, 다른 코드 사이에 섞이지 않고 그것들을 함께 놓는 것이 가장 좋다.가장 간단한 경우 이동 문구만 사용하면 모일 수 있다.다음 예와 같습니다.
    const name = getName()
    const age = getAge()
    let revenue
    const address = getAddress()
    // ...
    const name = getName()
    const age = getAge()
    const address = getAddress()
    
    let revenue
    // ...

    두 데이터 영역의 기능이 다르기 때문에 이동 문장을 제외하고 나는 그것들 사이에 한 줄을 비워서 사람들로 하여금 그것들 사이의 차이를 더욱 쉽게 구분하게 한다.
    내포 조건 표현식
    여러 조건 표현식이 중첩되면 코드를 읽기 어려워집니다.
    function getPayAmount() {
        if (isDead) {
            return deadAmount()
        } else {
            if (isSeparated) {
                return separatedAmount()
            } else if (isRetired) {
                return retireAmount()
            } else {
                return normalAmount()
            }
        }
    }
    function getPayAmount() {
        if (isDead) return deadAmount()
        if (isSeparated) return separatedAmount()
        if (isRetired) return retireAmount()
        return normalAmount()
    }

    조건 표현식을 분리한 후 코드의 읽기성이 크게 강화되었다.
    조회 함수와 수정 함수를 분리하다
    일반적인 조회 함수는 모두 값을 얻는 데 쓰인다. 예를 들어getUserData(),getAget(),getName() 등이다.때때로, 우리는 편의를 위해 검색 함수에 다른 기능을 추가할 수도 있다.예를 들어 다음 함수는 다음과 같습니다.
    function getValue() {
        let result = 0
        this.data.forEach(val => result += val)
        //             
        sendBill()
        return result
    }

    절대 이렇게 하지 마세요. 함수의 중요한 기능은 직책 분리입니다.그래서 우리는 그것들을 분리해야 한다.
    function getValue() {
        let result = 0
        this.data.forEach(val => result += val)
        return result
    }
    
    function sendBill() {
        // ...
    }

    이런 함수의 기능은 매우 뚜렷하다.
    소결
    옛사람이 말하기를 책을 다 믿는 것보다 책이 없는 것이 낫다고 했다.《재구성2》도 예외가 아니다. 이 책을 볼 때 반드시 비판적인 시선을 가지고 읽어야 한다.
    안에 소개된 재구성 기법은 수백 가지에 달하지만 모두 적용되는 것은 아니다.그래서 반드시 취사가 있어야 한다. 안에 있는 유용한 수법을 베껴서 수시로 몇 번 보아야 한다.이렇게 하면 코드를 쓸 때 재구성이 호흡처럼 자연스러워져서 사용해도 모른다.
    참고 자료
  • 《재구성2》

  • 너를 데리고 전방 공사에 들어가겠다 전체 텍스트 카탈로그:
  • 기술 선형: 어떻게 기술 선형을 진행합니까?
  • 통일규범: 어떻게 규범을 제정하고 도구를 이용하여 규범이 엄격하게 집행되도록 보증합니까?
  • 프런트엔드 구성 요소화: 모듈식, 구성 요소화란?
  • 테스트: 유닛 테스트와 E2E 테스트를 어떻게 씁니까?
  • 구축 도구: 구축 도구는 어떤 것들이 있습니까?어떤 기능과 장점이 있습니까?
  • 배포 자동화: Jenkins, Github Actions 배포 프로젝트를 어떻게 활용합니까?
  • 전단 모니터링: 전단 모니터링 원리와 sentry를 어떻게 이용하여 프로젝트에 대한 모니터링을 실시하는지 설명한다.
  • 성능 최적화(一): 사이트의 성능을 어떻게 측정합니까?어떤 실용적인 성능 최적화 규칙이 있습니까?
  • 성능 최적화(二): 사이트의 성능을 어떻게 검사합니까?어떤 실용적인 성능 최적화 규칙이 있습니까?
  • 재구성: 왜 재구성을 해요?재구성에는 어떤 수법이 있습니까?
  • 마이크로 서비스: 마이크로 서비스는 무엇입니까?어떻게 마이크로 서비스 프로젝트를 세웁니까?
  • 세븐스: 세븐스란 무엇입니까?Serverless 사용 방법
  • 좋은 웹페이지 즐겨찾기