큰 방법을 리팩터링 할 때 어떤 것도 깨지 않도록 어떻게 도움이됩니까?


10

현재 단위 테스트가없는 대형 코드베이스의 일부를 리팩토링하고 있습니다. 코드를 리팩토링하려고 시도했습니다. 즉, 코드가 수행하는 작업과 변경 사항으로 인해 변경되지 않는 것을 추측하려고 시도했지만 성공하지 못했습니다. 코드베이스 주변의 모든 기능을 임의로 중단합니다.

리팩토링에는 레거시 C # 코드를보다 기능적인 스타일로 이동 (레거시 코드는 LINQ를 포함한 .NET Framework 3 이상의 기능을 사용하지 않음), 코드의 이점이있는 곳에 제네릭 추가 등이 포함됩니다.

비용이 많이 들기 때문에 공식적인 방법을 사용할 수 없습니다 .

다른 한편으로, 나는 아무리 많은 비용이 들더라도 적어도 "리팩토링 된 레거시 코드는 단위 테스트와 함께 제공 될 것" 규칙을 엄격히 준수해야한다고 가정합니다. 문제는 500 LOC 개인 메소드의 작은 부분을 리팩터링 할 때 단위 테스트를 추가하는 것이 어려운 작업으로 보인다는 것입니다.

주어진 코드에 어떤 단위 테스트가 관련되는지 아는 데 무엇이 도움이됩니까? 나는 코드의 정적 분석이 어떻게 든 도움이 될 것이라고 생각하지만, 내가 사용할 수있는 도구와 기술은 무엇입니까?

  • 어떤 단위 테스트를 만들어야하는지 정확히 알고

  • 그리고 / 또는 내가 한 변경 사항이 원래 코드와 다르게 실행되는 방식으로 원본 코드에 영향을 주 었는지 알고 있습니까?


작문 단위 시험을 작성하면이 프로젝트의 시간이 늘어난다는 이유는 무엇입니까? 많은 지지자들은 동의하지 않을 것입니다. 그러나 그것은 또한 당신이 그것들을 쓸 수있는 능력에 달려 있습니다.
JeffO

나는 그것이 프로젝트의 전체 시간을 증가시킬 것이라고 말하지 않는다. 내가 말하고 싶은 것은 단기적으로 시간이 증가한다는 것입니다 (즉 , 코드를 리팩토링 할 때 지금 당장 보내는 시간 ).
Arseni Mourzenko

1
당신이 사용하는 완하지 않을 formal methods in software development이 술어 논리를 사용하여 프로그램의 정확성을 증명하는 데 사용되며 큰 코드베이스를 리팩토링에 적용이되지 않기 때문에 어쨌든. 코드를 증명하기 위해 일반적으로 사용되는 공식적인 방법은 의료 응용 프로그램과 같은 영역에서 올바르게 작동합니다. 비용이 많이 들기 때문에 자주 사용하지 않는 것이 좋습니다.
Mushy

ReSharper 의 리 팩터 옵션과 같은 유용한 도구를 사용 하면 이러한 작업을 훨씬 쉽게 수행 할 수 있습니다. 이와 같은 상황에서는 돈이 가치 가 있습니다.
billy.bob

1
완전한 대답은 아니지만 멍청한 기술입니다. 다른 모든 리팩토링 기술이 실패했을 때 놀랍게도 효과적입니다. 새 클래스를 만들고 함수를 이미 존재하는 코드를 사용하여 별도의 함수로 분리하고 50 개 줄마다 끊어집니다. 여러 함수에서 멤버와 공유되는 로컬 멤버 인 경우 개별 함수가 내 머리에 더 잘 맞고 전체 로직을 통해 스레드 된 부분을 멤버에서 볼 수 있습니다. 이것은 최종 목표가 아니며 레거시 혼란을 안전하게 리팩토링 할 수있는 안전한 방법입니다.
Jimmy Hoffa

답변:


12

나는 비슷한 과제를 겪었다. 레거시 코드와 작업 책은 훌륭한 자원입니다,하지만 당신은 단위 테스트에 신발 경적이 작업을 지원하기 위해 할 수있는 가정이있다. 때로는 불가능합니다.

내 고고학 작업 (이와 같은 레거시 코드에 대한 유지 관리 용어)에서 나는 당신이 요약 한 것과 비슷한 접근법을 따릅니다.

  • 루틴이 현재하고있는 일에 대한 확실한 이해로 시작하십시오.
  • 동시에 루틴이 수행 해야 할 작업을 식별하십시오 . 많은 사람들이이 글 머리 기호와 이전 글 머리 기호는 동일하다고 생각하지만 미묘한 차이가 있습니다. 종종 루틴이 수행했던 작업을 수행하는 경우 유지 보수 변경 사항을 적용하지 않을 수 있습니다.
  • 루틴을 통해 일부 샘플을 실행하고 메인 라인 경로와 함께 경계 사례, 관련 오류 경로를 확인하십시오. 내 경험은 부수적 손상 (기능 손상)이 정확히 동일한 방식으로 구현되지 않은 경계 조건에서 발생한다는 것입니다.
  • 이러한 샘플 사례 후에는 반드시 유지할 필요가없는 항목을 식별하십시오. 다시 말하지만, 나는 다른 곳에서 부수적 인 손상을 초래하는 부작용과 같은 부작용을 발견했습니다.

이 시점에서 해당 루틴에 의해 노출 및 / 또는 조작 된 후보 목록이 있어야합니다. 이러한 조작 중 일부는 부주의 할 수 있습니다. 이제 findstr후보 목록의 항목을 참조 할 수있는 다른 영역을 이해하기 위해 IDE와 IDE를 사용 합니다. 그 참고 문헌이 어떻게 작동하고 그 본질이 무엇인지 이해하는 데 시간을 할애합니다.

마지막으로, 내가 원래의 일상의 영향을 이해한다고 생각한 후에는 한 번에 하나씩 변경을 수행하고 위에서 설명한 분석 단계를 다시 실행하여 변경이 예상대로 작동하는지 확인합니다. 작동합니다. 나는 특히 여러 가지 사항을 한 번에 변경하지 않도록 노력하고 있습니다. 때로는 여러 가지 변경 사항을 피할 수 있지만 한 번에 하나씩 경로를 따라갈 수 있다면 그것이 내 취향입니다.

요컨대, 나의 접근 방식은 당신이 계획 한 것과 비슷합니다. 많은 준비 작업입니다. 그런 다음 신중하고 개인적인 변화를 취하십시오. 그런 다음 확인, 확인, 확인하십시오.


2
"고고학"단독 사용의 경우 +1 그게 내가이 활동을 설명 할 때 사용하는 용어이고 나는 그 넣을 수있는 좋은 방법이라고 생각 (도 대답은 좋은 줄 알았는데 - 내가 그 얕은 정말 아니에요)
에릭 디트리히

10

큰 방법을 리팩터링 할 때 어떤 것도 깨지 않도록 어떻게 도움이됩니까?

짧은 대답 : 작은 단계.

문제는 500 LOC 개인 메소드의 작은 부분을 리팩터링 할 때 단위 테스트를 추가하는 것이 어려운 작업으로 보인다는 것입니다.

다음 단계를 고려하십시오.

  1. 구현을 다른 (비공개) 함수로 옮기고 호출을 위임하십시오.

    // old:
    private int ugly500loc(int parameters) {
        // 500 LOC here
    }
    
    // new:    
    private int ugly500loc_old(int parameters) {
        // 500 LOC here
    }
    
    private void ugly500loc(int parameters) {
        return ugly500loc_old(parameters);
    }
    
  2. 모든 입력 및 출력에 대해 원래 기능에 로깅 코드를 추가하십시오 (로깅이 실패하지 않도록하십시오).

    private void ugly500loc(int parameters) {
        static int call_count = 0;
        int current = ++call_count;
        save_to_file(current, parameters);
        int result = ugly500loc_old(parameters);
        save_to_file(current, result); // result, any exceptions, etc.
        return result;
    }
    

    응용 프로그램을 실행하고 사용 가능한 모든 작업 (유효한 사용, 유효하지 않은 사용, 일반적인 사용, 비정형 사용 등)을 수행하십시오.

  3. 이제 max(call_count)테스트를 작성하기위한 입력 및 출력 세트가 있습니다. 모든 매개 변수 / 결과 세트를 반복하고 루프에서 실행 하는 단일 테스트를 작성할 수 있습니다. 특정 조합을 실행하는 추가 테스트를 작성할 수도 있습니다 (특정 i / o 세트의 통과를 신속하게 확인하는 데 사용).

  4. // 500 LOC here다시 ugly500loc기능 으로 이동 하고 로깅 기능을 제거하십시오.

  5. 큰 함수에서 함수 추출을 시작하고 (다른 것은하지 말고 함수를 추출하십시오) 테스트를 실행하십시오. 이 후 500LOC 기능 대신 리팩토링 할 기능이 더 적어야합니다.

  6. 그 이후 행복하게 살았습니다.


3

일반적으로 단위 테스트가 진행됩니다.

전류가 예상대로 작동하는지 입증하는 필요한 테스트를 수행하십시오. 시간이 걸리면 마지막 테스트를 통해 출력에 자신감을 가져야합니다.

주어진 코드에 어떤 단위 테스트가 관련되는지 아는 데 무엇이 도움이됩니까?

코드 조각을 리팩토링하는 과정에서 코드의 기능과 영향을 정확히 알아야합니다. 따라서 기본적으로 영향을받는 모든 영역을 테스트해야합니다. 시간이 많이 걸리지 만 리팩토링 프로세스에서 예상되는 결과입니다.

그런 다음 아무런 문제없이 모든 것을 찢을 수 있습니다.

AFAIK, 이것에 대한 방탄 기술은 없습니다 ... 당신은 단지 체계적이어야합니다 (당신이 편안하다고 느끼는 방법에 관계없이), 많은 시간과 많은 인내심이 필요합니다! :)

건배와 행운을 빕니다!

알렉스


코드 적용 도구는 여기에 필수적입니다. 검사를 통해 복잡한 방법을 통해 모든 경로를 다뤘다는 것을 확인하기는 어렵습니다. KitchenSinkMethodTest01 () ... KitchenSinkMethodTest17 ()은 1-45, 48-220, 245-399 및 488-500 행을 포함하지만 코드 사이에는 영향을주지 않습니다. 훨씬 간단하게 작성하기 위해 어떤 추가 테스트가 필요한지 알아낼 것입니다.
Dan은
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.