재구성 재구성은 프로그램의 원래 행위를 바꾸지 않는 토대에서 기존 코드를 수정하여 내부 구조를 개선하는 것을 말한다.
언제 기능 추가 시 재구성, 버그 복구 시 재구성, 코드 심사 시 재구성;
기존 코드를 재구성하지 말아야 할 때가 너무 혼란스럽거나 정상적으로 작동하지 못할 때가 언제인지 프로젝트는 이미 최종 기한에 가까워졌다.
재구성의 장점 1.재구성은 소프트웨어 디자인 프로젝트가 끝난 후 후기의 버그 복구, 수요 증가로 인해 코드가 점점 부패하고 변질될 수 있다.군더더기, 구조가 혼란스럽고 이해하기 어렵고 유지하기 어렵고 확장하기 어렵다.어떤 오류를 수정하려면 수정해야 할 코드가 많을 수도 있습니다.소프트웨어 개발에서 유일하게 변하지 않는 것은 변화다.소프트웨어가 수요 변경으로 인해 점차 퇴화되기 시작할 때 소프트웨어 재구축을 활용하여 우리의 구조를 개선하고 소프트웨어 수요의 변화에 다시 적응하도록 한다.일상적인 재구성은 코드의 원래 형태를 유지할 수 있다.
재구성은 코드를 이해할 때 자신의 이해에 따라 수정하여 코드를 더욱 간결하게 하는 데 도움을 줄 수 있다. 따라서 이전에 보지 못했던 디자인 차원의 것을 볼 수 있다. 재구성 원칙: 빠른 걸음으로 민첩한 소프트웨어 개발의 관건적인 활동은 바로 교체이다. 진화식 디자인, 증량 개발을 제창한다.재구성에서도 비슷한 전략을 취해야 한다. 작은 걸음으로 빨리 달리고 진화식 재구성이다.매번 버그가 들어오지 않도록 조금씩 수정하고 테스트합니다.너무 많이 바꾸면 결과를 통제할 수 없게 되고 예상치 못한 버그가 많이 발생할 수 있다.
코드 나쁜 맛 불필요한 코드, 명명 불규범, 중복 코드, 과장 함수, 비대한 종류, 파라미터 과다, 과도한 디자인, 과다 주석 등등.
자주 사용하는 재구성 기교(건의)
코드 스타일은 기존 코드에서 재구성되고 재구성된 코드는 가능한 한 이전의 좋은 코드 스타일(명명 규칙)과 일치해야 한다.원래 좋지 않은 스타일, 예를 들어 변수와 연산자 사이에 빈칸이 추가되지 않았고, 함수 매개 변수 사이의 빈칸, 함수 사이의 한 줄이 비어 있지 않은 등은 수정해야 한다. 불필요한 코드의 함수, 클래스, 변수를 삭제하고 더 이상 작동하지 않으면 삭제해야 한다.지나치게 많은 불필요한 코드는 다른 사람이 코드를 이해하는 어려움을 증가시키고 컴파일된 목표 파일을 증대시킬 수 있다.국부 변수는 사용하기 전에 정의해야 하며 함수 입구에서 한 번 정의할 필요가 없다. 흐리멍덩한 방법명을 바꾸면 코드의 가용성에 영향을 줄 수 있습니다.이러한 모호하고 명확하지 않은 명칭은 의미 있고 업무와 관련된 명칭으로 바꾸어 코드가 클래스, 인터페이스, 방법, 변수, 파라미터 등의 명칭을 더욱 잘 이해하고 이해하도록 도와야 한다.명칭은 이 함수, 변수, 유형의 직책을 비교적 명확하게 설명할 수 있어야 한다.좋은 명칭은 주석의 목적에 도달할 수 있다.general Call, set Price And Weight와 유사하면 좋은 이름이 아니다. 상수 교체 마법 숫자는 의미가 있고 곳곳에서 사용되는 마법 숫자에 대해 상수 대체를 사용해야 한다.이것은 코드의 가독성과 이해성을 크게 강화할 수 있다. 함수 매개 변수가 너무 많으면 함수나 방법의 매개 변수가 너무 많으면 그 중의 매개 변수를 바꾸면 여러 호출점에서 변경해야 한다.여러 개의 매개 변수를 하나의 구조체나 클래스로 봉인할 수 있습니다. 비대함수, 클래스가 부담하는 여러 직책 설계 모델을 분해하는 데 하나의 원칙을 단일 직책 원칙이라고 한다.즉 함수, 클래스, 인터페이스가 맡은 직책은 가능한 한 단일해야 한다는 것이다.과도한 직책은 함수체, 클래스 방법이 너무 방대하고(수백 수천 줄 코드), 클래스 직책이 코드 읽기에 너무 많은 영향을 미친다는 것이 그 중 하나이다.둘째, 중복 코드가 존재할 수 있다. 중복 코드는 코드 복사를 통해 이루어지기 때문에 오류가 확산될 수 있다.그 세 가지 직책에 여러 가지 변화점이 존재하기 때문에 그 중의 한 직책을 수정할 때 다른 코드에 영향을 줄 수 있고 여러 직책의 결합성이 커서 오류를 도입할 수 있다. 실제 사용에서 함수, 인터페이스, 방법의 직책이 단일하도록 해야 한다.가능한 한 직책이 단일하도록 하다.
너무 큰 클래스를 여러 클래스로 나누고 한 클래스가 맡은 여러 직책을 여러 클래스로 나누어 각 클래스의 직책이 상대적으로 단일하도록 한다.방법: 기존 클래스의 방법과 속성을 새 클래스로 이동합니다.어떤 종류는 다른 종류에 정의해야 할 방법을 포함하고 있기 때문에 너무 비대하다.이런 방법도 마땅히 적당한 종류로 옮겨야 한다.예를 들어Ui 상호작용을 담당하는 기능이 업무 논리와 분리되고 데이터베이스 접근과 업무 논리가 서로 다른 유형으로 분리되면 데이터베이스 접근에 간접층을 추가하여 서로 다른 데이터베이스의 변화가 업무 논리에 미치는 영향을 호환할 수 있다. 너무 긴 방법은 너무 긴 함수를 여러 개의 이름이 좋은 작은 함수로 분해해야 한다.이해하기 쉽고 복용성이 우수하다.많은 프로그래머들이 성능 손실을 가져올까 봐 걱정하는데, 분리된 여러 개의 작은 함수 호출의 성능 소모는 매우 적다.가져오는 이익보다 소홀히 해서는 안 된다.만약 확실히 성능 손실을 초래한다면 재구축을 통해 성능을 개선할 수 있다. 중복 코드 중복 코드를 제거하면 대상 파일의 크기가 커집니다.코드 복사를 통해 이루어지는 경우가 많아 오류가 확산될 수 있다. 함수로 추출한다.중복 코드를 추출하여 독립 함수로 정의하면 함수의 입도가 작아 복용할 기회가 크다.일단 수정이 필요하다면 한 곳만 수정해야 하며, 직책이 단일하면 이해하기 쉽다. 추출 방법은 중복 코드가 같은 계승 체계에 있으면 기류로 추출할 수 있는 방법이다.완전히 중복되지 않고 미세한 차이가 있으면 템플릿 방법 모드를 사용할 수 있습니다. 상속이 범람하면 상속과 조합을 통해 한 종류가 다른 종류의 기능을 얻을 수 있다.그러나 상속을 사용할 때 자류와 부류는 강한 의존 관계이다.부모 포인터를 사용하거나 인용하는 곳에서는 부모 포인터를 부모 포인터로 대체할 수 있습니다.즉 두 종류 사이에 is-a 관계가 확실히 존재할 때만 계승을 사용할 수 있다는 것이다.강한 의존 관계로 인해 자류 부류의 결합성이 매우 강하다.조합에 비해 의존이 약해지고has-a관계를 만족시킬 때 조합을 통해 실현할 수 있다. 코일의 복잡도를 적당히 낮추어 하나의 모듈이 구조를 판정하는 복잡도를 측정하고 모든 가능한 상황을 덮어쓰는 데 가장 적게 사용하는 테스트 용례수로 이해할 수 있다.복잡도가 높은 코드 판단 논리는 복잡하고 버그가 도입될 수 있으며 가독성이 떨어진다.권의 복잡도는 주로 분기문(if,else,switch 등)의 개수와 관련이 있다.코드에 비교적 많은 분기 문구가 함유되어 있으면 논리의 복잡도가 증가할 것이다.목적은 핵심 유형, 핵심 방법의 복잡도를 낮추고 소프트웨어의 위험을 낮추며 소프트웨어의 확장성을 증가시킬 수 있다. 간소화 조건 표현식 합병 조건 표현식은 일련의 조건 판단이 같은 결과를 얻으면 이 테스트를 하나의 독립 함수로 통합할 수 있다. if(nHour <0 || nHour > 60)
return false;
if(nMinute < 0 || nMinute > 60)
return false;
if(nSec <0 || nSec > 60)
return false;
병합 후:
if(false == isTimeValid(nHour, nMinute, nSec))
{
return false;
}
bool isTimeValid(int nHour, int nMinute, int nSec)
{
if(nHour < 0 || nHour > 60 || nMinute < 0 || nMinute > 60 || nSec <0 || nSec > 60)
{
return false;
}
return true;
}
다중 덧붙이는 조건 표현식을 피하는 조건 표현식은 보통 두 가지 형식이 있다. 모든 지점은 정상적인 문장에 속하고 한 지점만 정상적인 문장에 속하며 나머지는 비정상적인 상황이다.만약 어떤 조건이 이상 조건에 속하고 흔하지 않다면 단독으로 이 조건을 검사해야 한다.끼워 넣으면 코드의 가독성이 떨어지므로 가능한 한 피해야 한다. if(NULL != pBuf)
{
if(false != func1())
{
if(false != Func2())
{
Func3();
}
}
}
수정 후:
if(NULL == pBuf)
return false;
if(false == func1())
return false;
if(false == func2())
return false;
func3();
덧씌우개가 없으면 구조가 더욱 뚜렷하고 이해하기 쉽다.
조건식 대신 다태적 표현식(if else switch case)을 사용하면 특정 조건식에 유형에 따라 다른 행위가 존재할 수 있다.원시 함수를 추상 함수로 성명하고 조건 표현식의 각 지점을 하위 클래스에 넣고 다시 쓰는 방법을 고려할 수 있다.여러 가지 조건 표현식을 작성할 필요가 없고, 새로운 형식을 추가하려면, 새로운 하위 클래스를 만들고 다시 쓰기만 하면 됩니다.이러한 변경 사항은 클래스 사용자에게 투명하기 때문에 상부에서 변경할 필요가 없습니다. 과도한 디자인을 피하는 과도한 디자인은 코드의 유연성과 복잡성이 필요를 초과한 것을 말한다.코드는 현재의 수요를 충족시키고 확장 가능한 여지를 남겨야 한다.미래의 변화에 대해 너무 많이 생각하지 말고 조금도 고려하지 않을 수도 없다.처음에는 수요가 명확하지 않거나 우리가 수요에 대한 이해가 명확하지 않아서 모든 변화를 고려할 수 없다. 왜냐하면 변화는 여러 방향에서 나올 수 있기 때문이다.모든 방향이 지나치게 앞서가는 디자인을 고려하면 우리의 코드가 매우 복잡해질 것이다.수요가 명확하지 않을 때, 많은 앞선 디자인들이 모두 쓸데없는 것이다.그 중에서 가장 변화가 발생할 수 있는 몇 가지 방향을 선택하고 디자인 모델을 사용하여 이러한 변화를 호환할 수 있다.후기에 우리가 수요에 대한 이해가 깊어지거나 수요가 어느 방향에서 확실히 변화가 생겼을 때 우리는 다시 고개를 돌려 재구성을 통해 우리의 디자인을 개선하고 이 변화를 호환하도록 한다. 같은 방향에서 온 같은 권총의 총알에 한 번 맞는 것을 허락한다는 비유가 있다.네가 맞은 후에, 너는 이 방향이 매우 위험하다는 것을 깨닫고, 즉시 동작을 취해야 한다.만약 반응이 둔하다면, 다시 맞은 것은 용서할 수 없는 것이다.
추천서적: 재구성-기존 코드 개선 디자인