따라서 일부 사람들은 다음과 같은 사실을 이해할 수 없습니다. 리팩토링 는 실제로 프로그래밍의 한 영역이며 프로그래머의 업무에서 매우 중요한 부분이기도 합니다. 코드는 계속 진화하고 있으며 새로운 기능을 추가할 수 있는 가능성이 있는 한 수정될 것입니다. 그러나 더 이상 새로운 기능을 효과적으로 추가할 수 없는 형태가 될 수도 있고 전체 프로그램을 다시 작성하는 것이 더 쉬울 수도 있습니다.
리팩터링이란 무엇인가요?
일반적으로 코드의 관찰 가능한 동작에 영향을 주지 않고 일련의 리팩터링 변환을 적용하여 코드의 구조를 변경한다는 대답을 듣게 됩니다. 이는 사실입니다. 최근에 저는 다음과 같은 정의도 발견했습니다. 마틴 파울러 그의 책에서 "기존 코드의 디자인 개선" 에서 다음과 같이 설명합니다. 리팩토링 를 "작은 발걸음으로 큰 변화를 만드는 것"으로 정의합니다. 그는 다음과 같이 설명합니다. 리팩토링 의 운영에 영향을 미치지 않는 코드 변경으로 생각하지만, 그는 작은 단계로 진행해야 한다고 강조합니다.
이 책은 또한 다음과 같이 주장합니다. 리팩토링 는 코드 작동에 영향을 미치지 않으며 언제든지 테스트를 통과하는 데 아무런 영향을 미치지 않는다는 점을 지적합니다. 안전하게 수행하는 방법을 단계별로 설명합니다. 리팩토링. 그의 책은 일상 업무에서 사용할 수 있는 간단한 트릭을 설명하기 때문에 마음에 들었습니다.
리팩터링이 필요한 이유는 무엇인가요?
새로운 기능을 도입하고 싶은데 현재 버전의 코드가 이를 허용하지 않거나 코드를 변경하지 않으면 더 어려울 때 가장 자주 필요할 수 있습니다. 또한 더 많은 기능을 추가하는 것이 시간적으로 이익이 되지 않는 경우, 즉 코드를 처음부터 다시 작성하는 것이 더 빠를 때 유용합니다. 가끔 잊어버리는 경우가 있습니다. 리팩토링 를 사용하면 코드를 더 깔끔하고 가독성 있게 만들 수 있습니다. Martin은 자신의 책에서 코드에서 불쾌한 냄새가 느껴질 때 어떻게 리팩터링을 수행하는지, 그리고 그 방법을 설명합니다, "항상 더 나은 여지를 남깁니다". 그리고 그는 리팩터링을 일상적인 코드 작업의 요소로 간주하여 저를 놀라게 했습니다. 저에게는 코드가 직관적이지 않은 경우가 많아서 코드를 이해하는 데 약간의 어려움이 있었습니다.
잘 설계된 프로그램의 특징은 다음과 같습니다. 모듈성덕분에 코드의 일부만 알면 대부분의 수정 사항을 도입하는 데 충분합니다. 또한 모듈화는 새로운 사람들이 더 쉽게 들어와서 더 효율적으로 작업을 시작할 수 있게 해줍니다. 이러한 모듈성을 달성하려면 관련 프로그램 요소를 함께 그룹화해야 하며, 그 연결은 이해하기 쉽고 찾기 쉬워야 합니다. 이를 달성하는 방법에 대한 정답은 없습니다. 코드가 더 잘 작동하는 방법을 점점 더 많이 알고 이해하게 되면 요소를 그룹화할 수 있지만 때로는 테스트하고 확인해야 할 때도 있습니다.
의 리팩토링 규칙 중 하나는 YAGNI'You Aren't Gonna Need It'의 약자로, 다음에서 유래했습니다. 익스트림 프로그래밍(XP) 주로 다음에서 사용됩니다. 애자일 소프트웨어 개발 팀. 간단히 말하자면, YAGNI 는 최신 작업만 수행해야 한다고 말합니다. 이는 기본적으로 미래에 필요할지라도 지금 당장 해서는 안 된다는 뜻입니다. 하지만 더 이상의 확장을 막아서도 안 되며, 바로 여기서 모듈성이 중요해집니다.
다음에 대해 이야기할 때 리팩토링에서 가장 필수적인 요소 중 하나인 테스트에 대해 언급해야 합니다. In 리팩토링코드가 여전히 작동하는지 확인해야 합니다. 리팩토링 는 작동 방식이 아니라 구조를 변경하므로 모든 테스트를 통과해야 합니다. 작은 변환을 할 때마다 작업 중인 코드 부분에 대한 테스트를 실행하는 것이 가장 좋습니다. 모든 것이 정상적으로 작동하는지 확인하고 전체 작업 시간을 단축할 수 있습니다. 한 발 물러서서 무언가를 망가뜨린 변환을 찾느라 시간을 낭비하지 않도록 가능한 한 자주 테스트를 실행하라는 것이 Martin이 그의 책에서 이야기하는 내용입니다.
코드 리팩토링 테스트 없이 코드를 작성하는 것은 번거롭고 문제가 발생할 가능성이 큽니다. 가능하다면 코드가 작동한다는 확신을 줄 수 있는 몇 가지 기본 테스트만이라도 추가하는 것이 가장 좋습니다.
아래 나열된 변환은 예시일 뿐이지만 일상적인 프로그래밍에 실제로 도움이 됩니다:
- 함수 추출 및 변수 추출 - 함수가 너무 길면 추출할 수 있는 작은 함수가 있는지 확인합니다. 긴 줄도 마찬가지입니다. 이러한 변환은 코드에서 중복을 찾는 데 도움이 될 수 있습니다. 작은 함수 덕분에 코드가 더 명확하고 이해하기 쉬워집니다,
- 함수 및 변수 이름 바꾸기 - 올바른 명명 규칙을 사용하는 것은 좋은 프로그래밍을 위해 필수적입니다. 변수 이름은 잘 선택하면 코드에 대해 많은 것을 알 수 있습니다,
- 함수를 클래스로 그룹화 - 이 변경 사항은 클래스의 길이를 줄일 수 있으므로 두 클래스가 유사한 작업을 수행할 때 유용합니다,
- 중첩 문 재정의 - 조건이 특수한 경우를 검사하는 경우 조건이 발생하면 반환 문을 발행합니다. 이러한 유형의 테스트를 종종 가드 절이라고 합니다. 중첩된 조건문을 종료 문으로 바꾸면 코드의 강조점이 변경됩니다. if-else 구조는 두 변형에 동일한 가중치를 할당합니다. 코드를 읽는 사람에게는 각 변형이 똑같이 가능성이 있고 중요하다는 메시지를 전달합니다,
- 특수 케이스 소개 - 코드에서 특정 조건을 여러 번 사용하는 경우 별도의 구조를 만드는 것이 좋습니다. 결과적으로 대부분의 특수 케이스 검사는 간단한 함수 호출로 대체할 수 있습니다. 특수 처리가 필요한 공통 값은 종종 null인 경우가 많습니다. 따라서 이 패턴을 흔히 제로 객체라고 부릅니다. 그러나 이 접근 방식은 모든 특수한 경우에 사용할 수 있습니다,
- 조건부 명령어 다형성 교체.
예
이 문서는 리팩토링 에 대한 예제가 필요합니다. 아래에서 간단한 리팩터링 샘플을 보여드리겠습니다. 중첩된 문 재정의하기 그리고 조건부 명령어 다형성 교체. 실생활에서 식물에 물을 주는 방법에 대한 정보가 포함된 해시를 반환하는 프로그램 함수가 있다고 가정해 보겠습니다. 이러한 정보는 모델에 있을 수도 있지만, 이 예제에서는 함수 안에 있습니다.
def watering_info(plant)
result = {}
if plant.is_a? Suculent || plant.is_a? 선인장
result = { water_amount: "조금 " , how_to: "바닥에서", watering_duration: "2주" }
elsif plant.is_a? 알로카시아 || plant.is_a? Maranta
결과 = { water_amount: "많은 양", how_to: "원하는대로", watering_duration: "5일" }
elsif plant.is_a? 페페로미아
결과 = { water_amount: "디센트 양",
how_to: "바닥에서! 잎에 물이 닿는 것을 싫어합니다",
watering_duration: "1주일" }
else
result = { water_amount: "디센트 양",
how_to: "원하는 대로",
watering_duration: "1주일"
}
end
결과 반환
end
반환할지 여부를 변경하는 것입니다:
if plant.isa? Suculent || plant.isa? Cactus
결과 = { 물량: "조금 " , howto: "바닥에서",
To
리턴 { 물_양: "조금 " , how_to: "바닥에서",watering_duration: "2주" } if plant.is_a? Suculent || plant.is_a? 선인장
반환 { 물금액: "조금 " , 방법에 "바닥에서", 급수기간: "2 주" } if plant.isa? Suculent || plant.is_a? Cactus
이렇게 모든 것을 반복하여 다음과 같은 함수가 나올 때까지 계속합니다:
def watering_info(plant)
반환 결과 = { wateramount: "조금 " , howto: "바닥에서", 물주기 기간: "2주" } if plant.isa? Suculent || plant.is_a? 선인장
반환 결과 = { wateramount: "많은 양", howto: "원하는 대로", 물주기 기간: "5일" } if plant.isa? 알로카시아 || plant.is_a? Maranta
반환 결과 = { water_amount: "디센트 양",
howto: "바닥에서! 잎에 물이 닿는 것을 싫어합니다",
물주기 기간: "1주" } if plant.is_a? 페페로미아
반환 결과 = { water_amount: "디센트 양",
how_to: "원하는 대로",
watering_duration: "1주일"
}
end
마지막에 우리는 이미 반환 결과를 얻었습니다. 그리고 이 작업을 단계별로 수행하고 모든 변경 사항을 테스트하는 것이 좋은 습관입니다. 이 if 블록을 스위치 케이스로 대체하면 즉시 더 좋아 보이고 매번 모든 if를 확인할 필요가 없습니다. 다음과 같이 보일 것입니다:
def watering_info(plant)
swich plant.class.to_string
케이스 다육식물, 선인장
{ 물량: "조금 " , howto: "바닥에서", watering_duration: "2주" }
사례 알로시아, 마란타
{ wateramount: "많은 양", howto: "원하는대로", watering_duration: "5일" }
사례 페페로미아
{ water_amount: "디센트 양",
how_to: "바닥부터! 나뭇잎에 물을 뿌려주세요",
watering_duration: "1주일" }
else
{ water_amount: "디센트 금액",
how_to: "원하는 대로",
watering_duration: "1주일" }
end
end
그런 다음 조건부 명령 다형성 교체하기. 올바른 값을 반환하는 함수가 있는 클래스를 만들어 적절한 위치로 전환하는 것입니다.
Suculent 클래스
...
def watering_info()
반환 { wateramount: "조금 " , howto: "바닥부터", watering_duration: "2주간" }
end
end
클래스 선인장
...
def watering_info()
반환 { wateramount: "조금 " , howto: "바닥부터", watering_duration: "2주간" }
end
end
클래스 알로시아
...
def watering_info
반환 { wateramount: "많은 양", howto: "원하는 대로", watering_duration: "5일" }
end
end
클래스 마란타
...
def watering_info
반환 { wateramount: "많은 양", howto: "원하는 대로", watering_duration: "5일" }
end
end
클래스 페페로미아
...
def watering_info
반환 { water_amount: "디센트 양",
how_to: "바닥부터! 잎에 물이 묻으면 안 돼요",
watering_duration: "1주일" }
end
end
클래스 플랜트
...
def watering_info
반환 { water_amount: "디센트 양",
how_to: "원하는 대로",
watering_duration: "1주일" }
end
end
그리고 기본 watering_infofunction에서 코드는 다음과 같습니다:
def watering_info(plant)
plant.map(&:watering_info)
end
물론 이 기능은 제거하고 해당 콘텐츠로 대체할 수 있습니다. 이 예제에서는 일반적인 리팩토링 패턴.
요약
리팩토링 가 큰 화제가 되고 있습니다. 이 글을 통해 더 많은 내용을 읽어보셨기를 바랍니다. 이 리팩토링 기술 는 버그를 잡아내고 깔끔한 코드 워크샵을 개선하는 데 도움이 됩니다. Martin의 책(기존 코드의 디자인 개선)을 읽어보시길 추천합니다. 이 책은 다음과 같은 매우 기본적이고 유용한 규칙을 담고 있습니다. 리팩토링. 저자는 완전한 설명과 동기 부여 및 실수를 피하는 방법에 대한 팁과 함께 다양한 변환을 단계별로 보여줍니다. 리팩토링. 다재다능한 기능으로 인해 프론트엔드 및 백엔드 개발자.
자세히 보기