입력되지 않은 것처럼 보이는 코드를 어떻게 안전하게 삭제합니까?


125

불필요한 코드를 발견했으며 컴파일러는이를 알지 못합니다. 이 코드를 삭제해도 회귀 현상이 발생하지 않도록하려면 어떻게해야합니까?

두 가지 아이디어가 떠 오릅니다.

  1. "간단하게"코드가 실행되어야하는지 여부에 따라 추론을 사용하십시오. 그러나 때로는 막대한 비즈니스 수익이 없기 때문에 복잡하고 시간이 많이 걸리는 작업 일 수 있습니다 (평가에 오류가 발생하기 쉽습니다).

  2. 해당 코드 섹션에 로깅을 배치하고 실제로 얼마나 자주 입력되는지 확인하십시오. 충분한 실행 후에는 코드를 제거해도 안전하다는 합리적인 확신이 있어야합니다.

더 나은 아이디어 나 정식 접근법과 같은 것이 있습니까?


55
버전 제어 히스토리를 보는 것이 도움이 될 수 있습니다. "데드 코드"는 언제 작성 되었습니까? 생성되었을 때 죽은 것처럼 보입니까? 다른 코드 (그 이후 수정 또는 삭제 된 코드)가 작성된 코드와 함께 체크인 했습니까?
ChrisW

9
리플렉션과 같은 메타 프로그래밍 형식이 사용 중이면 컴파일러를 신뢰할 수 없습니다. 기본 디렉토리의 적절한 grep은 필수 관행입니다. 여러 응용 프로그램에서 코드를 공유하는 것이 일반적이므로 올바른 디렉토리 계층에서 grep해야합니다.
Adam Caviness

16
"왜 귀찮게 하시겠습니까?"라고 물을 것입니다. 푸른 달에 한 번 호출되는 가장자리 케이스에 사용되면 문제가 발생했습니다. 절대 사용하지 않고 그대로두면 실행 파일이 조금 더 커집니다. 이것이 일부 임베디드 장치가 아니라면 큰 문제입니까? 그것에 의견을 남기고 생산적으로 시간을 사용하십시오.
mickeyf

40
@mickeyf 손상은 누군가 그 코드를 유지해야한다는 것입니다. 즉, 개발자는 자신이하는 일을 이해해야합니다. 상황이 변하면 개발자는이를 수정해야하고 주변의 코드는 이제 다른 작업을 수행해야합니다. 믿어 봐요, 당신이 쪼그려 앉은 채로두면 나중에 나중에 알아 내려고하는 사람에게는 큰 두통입니다.
jpmc26

9
@MichaelJ. 내 요점은 그것이 처음에 거기에 있었으면 안된다는 것입니다. 그리고 내가 떠나면 상황이 더 나빠집니다. 이제 다른 개발자가 문제를 조사해야합니다. 오래 머무를수록 이해하는 데 더 많은 시간이 걸립니다. 이것은 불필요한 코드 비용입니다.
jpmc26

답변:


112

100 % 단위 테스트 적용 범위를 가진 완벽한 판타지 세계에서는 삭제하고 단위 테스트를 실행하며 테스트가 빨간색으로 바뀌지 않으면 커밋합니다.

그러나 불행히도 매일 아침 일어나서 많은 코드가 단위 테스트가 없거나 가능한 경우 모든 가능한 경우를 다룰 수 있다고 믿을 수없는 거친 현실에 직면해야합니다. 따라서 위험 / 보상을 고려하고 그만한 가치가 없다는 결론에 도달했습니다.

  • 보상 : 코드는 미래에 유지하기가 조금 더 쉽습니다.
  • 위험 : 내가 생각하지 않았던 모호한 일부 사례에서 코드를 깨뜨리고, 최소한 기대할 때 사고를 일으키며, 코드 품질 OCD를 충족시키고 비즈니스 가치없이 인식 할 수 있어야했기 때문에 오류가 발생했습니다. 코더가 아닌 이해 관계자에게

249
엔지니어가 10 ~ 12 년 동안 대부분 불필요한 코드를 제거하기 위해 "가치가없는"접근 방식을 따르는 대규모 소프트웨어 프로젝트의 상태를 관찰 한 후에는 이 방법을 권장 할 수 없습니다 .
njuffa

125
또한 단위 테스트는이 코드가 실제로 프로덕션에서 사용되는지 여부에 대해 아무 것도 알려주지 않습니다. 코드는 완벽하게 테스트 될 수 있지만 여전히 프로덕션에서는 사용되지 않으므로 불필요한 것입니다.
knub

8
내 경험상 그러한 프로젝트의 상태는 코드를 수정하는 "가치가없는"접근 방식으로 인한 것이 아니며, 항상 잘못된 코드가 처음부터 작성 되었기 때문입니다. 잘못된 코드를 작성하는 것은 실수이지만 코드 청소가 항상 가치가 있다고 생각하는 것은 실수입니다.
Weyland Yutani

42
@Weyland Yutani 그것은 내 경험과 전혀 일치하지 않습니다. 필자가 보았던 불필요한 코드의 대부분은 10 년 전에 존재했던 소프트웨어 사양, 하드웨어 플랫폼 또는 운영 체제 버전을 감안할 때 충분히 잘 작성되고 완벽하게 합리적이었습니다. 이전에는 툴 체인이나 하드웨어의 버그 등을 해결하는 데 필요했습니다. .
njuffa

20
대답은 학습을 진행하고 변화시키는 것의 가장 중요하고 중요한 이점 중 하나를 그리워합니다. 그것을 배운 후에는 나중에 구조 유지 보수 개발자를 돕기 위해 구조 (설명, 테스트)를 추가 할 수 있습니다. 결과를 모르기 때문에 무언가를 변경하지 않기로 선택하는 것은 선택이 무언가를 삭제하지 않더라도화물 컬트 프로그래밍입니다.
kojiro

84

이 과정에는 두 가지 반이 있습니다. 첫 번째는 코드가 실제로 죽었 음을 확인하는 것입니다. 두 번째는 잘못된 비용을 이해하고 올바르게 완화시키는 것입니다.

여기에 많은 답변이 전반에 대한 훌륭한 해결책이 있습니다. 정적 분석기와 같은 도구는 데드 코드를 식별하는 데 유용합니다. grep어떤 경우에는 친구가 될 수 있습니다. 내가 자주 취하는 한 가지 특이한 단계는 코드의 원래 목적이 무엇인지 식별하는 것입니다. “X는 더 이상 제품의 기능이 아니며 코드 세그먼트 Y는 기능 X를 지원하도록 설계되었습니다.”는“코드 세그먼트 Y의 목적이 보이지 않습니다.”라고 말하는 것보다 훨씬 쉽습니다.

후반부는 코드를 제거해야하는지에 대한 그리드 락을 깨는 핵심 단계입니다. 답변이 잘못되었다는 의미를 이해해야합니다. 대답이 틀리면 사람들이 죽을 경우주의를 기울이십시오! 어쩌면 코드 크래프트가 시간이 지남에 따라 발전한다는 것을 받아들이고 대신 더 많은 크래프팅을 작성하지 마십시오. 사람들이 죽지 않을 경우 자신을 어떻게 용서하는지 물어보십시오. 문제가 발생하여 고객 관계를 유지하는 경우 핫픽스를 보낼 수 있습니까? 이와 같은 문제를 찾기 위해 비용을 지불 한 Q & A 팀이 있습니까? 이러한 종류의 질문은 삭제 키를 누르기 전에 얼마나 확신해야 하는지를 이해하는 데 필수적입니다.

의견에서 rmun은 코드를 제거하기 전에 코드의 원래 목적을 이해하는 개념에 대한 훌륭한 표현을 지적했습니다. 인용문은 현재 체스터턴의 울타리 로 알려져 있습니다. 주석에 직접 인용하기에는 너무 크지 만 여기에 올바르게 인용 할 가치가 있다고 생각합니다.

그것들을 변형시키는 것과 구별되는 것들을 개혁하는 문제에는 분명하고 단순한 한 가지 원칙이있다. 아마도 역설이라고 불리는 원칙. 이 경우 특정 기관이나 법률이 있습니다. 단순성을 위해 도로를 가로 질러 울타리 나 문을 세웠습니다. 보다 현대적인 유형의 개혁가는 그것을 기꺼이 받아 들여서 말합니다.“저는 이것을 사용하지 않습니다. 보다 지능적인 유형의 개혁가가 대답 할 수있는 좋은 방법은 다음과 같습니다.“어떻게 사용하지 않으면 분명히 지울 수 없습니다. 저리 가서 생각하십시오. 그런 다음 다시 돌아와서 그 사용법을 볼 수 있다고 말하면, 나는 그것을 파기 할 수 있습니다.


14
체스터튼 펜스 (Kesterton 's Fence)는 생각이 순전히 발견에 의한 것이라고 생각하며, 고대 그리스 철학이 아니라 의지가 없다고 가정합니다. 과학적 방법은 더욱 현대적입니다. 구조를 제거한 결과를 결정하기위한 통제 된 실험을 고안하십시오. 확실히, 나는이 실험이 생산에서 이루어 지도록 무의미하게 제안하지 않을 것이다. 그러나 대안이없고 생산 시범 비용이 매우 높다면, 일부 코드가 존재하는 이유를 배울 수있는 안전한 수단을 제공하지 않는 직장을 빨리 떠나고 싶습니다. .
kojiro

15
@kojiro 그것은 사실입니다. "현대 개혁가"가 와서 "이 울타리가 왜 여기에 있는지 모르겠지만 인정합니다.하지만 체스터 톤은 괜찮을 것 같아요." 체스터 톤은 아마 그 정보에 만족할 것입니다.
Cort Ammon

41
VMS OS 커널 모드 클럭 디코딩 방법 SYS $ ASCTIM에는 춘분의 측면 드리프트를 수정하는 데 도움이되는 코드 줄이 포함되어 있습니다. DEC의 단위 테스트 중 어느 것도이 코드를 연습하지 않습니다. 2000-02-28의 23 : 59 : 59 : 999에 한 번 올바르게 실행되었습니다. 2400 년까지는 다시 실행되지 않습니다. 삭제하지 마십시오.
AI Breveleri

13
@AIBreveleri 나는 단지 여기에 Exchange가 아니라 이것을 설명하는 코드 자체에 주석이 있기를 바랍니다 .D
Kyle Strand

11
@KyleStrand 무슨 소리 야? 이것은 이다 문서. 다른 사람들이 StackExchange보다 정보를 찾을 수 있도록 중요한 정보를 넣을 수있는 더 좋은 곳을 생각할 수 있습니까? ;-)
Cort Ammon

43

또한 grep코드에서 함수 / 클래스 이름을 사용하는 경향이 있는데, 예를 들어 주석이나 문서 파일 또는 스크립트에 이름이 언급 된 경우와 같이 코드 분석기가 제공하지 않을 수있는 추가적인 이점이 있습니다. 소스 트리의 파일에서 grep을 실행하고 결과를 파일에 저장합니다. 일반적으로 결과는 압축 된 정보 (파일 이름 / 경로, 행 번호 및 이름이있는 행)를 제공하며, 이는 의미 적 의미없이 함수 / 클래스가 호출되거나 언급 된 위치에 대한 단서를 제공 할 수 있습니다 (코드 분석기와 달리) ) 및 파일 확장자에 관계없이 확실히 최고의 솔루션은 아니지만 분석에 대한 훌륭한 추가 기능입니다.


11
나는 downvoter가 아니지만, 의심되는 코드 섹션이 실행되지 않는다고 생각되면 완전한 함수 또는 클래스가 아니라 메소드 / 함수의 섹션입니까?
Tulains Córdova

9
언어에 따라 항상 신뢰할 수있는 것은 아닙니다. 일부 언어에서는 메소드 호출을 동적으로 수행 할 수 있습니다. 예 : php :$object->$variableMethod($arg1, $arg2);
Dezza

9
@ TulainsCórdova 그렇다면 이것은 아마도 좋은 해결책이 아닐 것입니다. 모든 잠재적 인 솔루션은 주어진 맥락에서 의미가 있다면 사용하십시오. 그러나 아마도 grep예를들 수 있습니다. 코드 섹션을 포함하는 함수는 함수의 사용법과 그 내용에 대한 힌트를 줄 수 있습니까?
piwi

7
"이름이 주석, 문서 파일 또는 스크립트에 언급 된 경우"-누군가 리플렉션을 사용하여 메소드를 호출하는 경우 (고급 / OO 언어를 사용하는 경우) 100 % 정확할 필요는 없지만 일부 언어는 메소드를 찾고 호출하는 매우 난해한 방법을 지원합니다.
aroth

함수를 사용할 수있는 모든 가능한 코드에 액세스 할 수있는 경우에 유용합니다. 그러나 코드가 라이브러리의 일부인 경우 검색 할 수없는 다른 것이 깨지지 않는다는 것을 어떻게 알 수 있습니까?
Kevin Shea

30
  • 죽은 것처럼 보이는 코드를 식별하십시오 (정적 분석 등).
  • 죽은 것으로 의심되는 코드가 호출때마다 로그 메시지를 추가하십시오 . 함수 / 메소드로 쉽습니다. 상수와 같은 정적 멤버를 사용하면 까다 롭습니다. 때로는 코드를 더 이상 사용되지 않는 것으로 표시하고 런타임에서 자동으로 메시지를 기록합니다. 그렇지 않으면 코드를 그대로 두십시오.
    • 죽은 모듈이로드 될 때 메시지를 기록합니다. 대부분의 언어에는로드시 정적 초기화를 실행할 수있는 방법이 있습니다.
    • 로그 메시지에 합리적인 스택 추적이 포함되어 있는지 확인하여 데드 코드라고하는 것이 무엇인지 이해 하십시오.
  • 모든 테스트 스위트를 통해 변경된 코드를 실행하십시오. 테스트 스위트는 또한 자정을 건너는 것과 같은 특별한 시간, 1/4 분기, 1 년 차례 등을 테스트해야합니다. 로그를보고 죽은 내용에 대한 이해를 업데이트하십시오. 단위 테스트는 데드 코드를 구체적으로 테스트 할 수 있지만 다른 단위 테스트 및 통합 테스트는 해당 코드를 건드리지 않습니다.
  • 몇 주 동안 프로덕션 환경에서 변경된 코드를 실행하십시오. 한 달에 한 번 ETL cron 작업과 같은 모든 주기적 프로세스가이 기간 동안 실행되는지 확인하십시오.
  • 로그를보십시오. 기록 된 것은 실제로 죽지 않았습니다. 죽은 코드의 나머지 부분을 통해 콜 그래프의 전이 폐쇄는 또한 이 호출되지 않은 경우에도, 잠재적으로 죽지 않았어. 분석하십시오. 어쩌면 일부 브랜치는 안전하게 죽었을 수도 있습니다 (예 : 현재 소멸 된 서비스의 API로 작업). 전체 모듈 / 클래스는 정의 된 상수에 대해서만로드 될 수 있으며 쉽게 폐기 할 수 있습니다.
  • 남은 것은 안전하게 죽어 제거 할 수 있습니다.

모든 것이 처음이므로 코드가 이전에 실행되지 않았다고해서 코드가 실행 경로가없는 경우 절대로 실행되지 않는다는 의미는 아닙니다. 즉, 실행할 수있는 것을 제거 하기 로 결정하는 것은 실행할 수 있는지 여부를 결정하는 것과 다른 프로세스입니다.

7
@nocomprende이 코드가 연말 기능에만 사용되고 테스트를 실행하는 경우 2 월-11 월이되면 정확히 어떤 일이 발생하는지 거의 1 년 동안 프로파일 링하더라도 사용법을 찾을 수 없습니다.
Erik

1
@ 9000 이론에 동의하지만 레거시 시스템에는 이러한 종류의 테스트를 방해 할 수있는 숨겨진 종속성이 있습니다. 테스트 예제가 작동하려면 일종의 시간적 결합이 있음을 알아야합니다. 시간적 커플 링이 테스트하는 코드 외부에 있다면 코드에서 볼 수 없으며 시간적 커플 링이 요인이라는 것을 알 수 있습니다. 예를 들어 silo A의 코드는 GAC에 설치됩니다 . 몇 년 전 사일로 B는 사일로 A의 데이터에 대해 실행해야하는 보고서에 대한 코드 경로를 추가하도록 사일로 A에 요청했습니다. 계속
Erik

1
@ 9000 계속 이제 사일로 B의 코드는 사일로 A의 코드를 보면 명확하지 않은 사일로 A의 코드에서 "죽은"코드 경로에 일시적으로 연결됩니다. 시간 결합은 사일로 B와 대화 할 줄 모르고 사일로 B의 코드에만 있기 때문에 어떻게이 시간 결합에 대한 단위 테스트를 하시겠습니까? 그럼에도 불구하고 시간은 코드 (사일로 A)의 요소가 아니므로 시간 테스트는 어떻게 생겼습니까?
Erik

2
누구든지 Y2k 패닉을 기억 하십니까? 일부 코드는 2100에 잘못 되었기 때문에 2000 년에 맞았습니다! 100 년에 한 번 또는 400 년에 한 번 발생할 수있는 잠재적 인 문제가있었습니다.
Steve Barnes

16

언급 된 기존 답변 외에도 여러 버전에서 반복적으로 코드를 제거 할 수 있습니다.

초기 버전에서는 코드 블록이 계속 작동하면서 사용 중단 경고를 표시 할 수 있습니다. 이후 버전에서는 코드 블록을 제거 할 수 있지만 사용자에게이 기능은 더 이상 사용되지 않으며 더 이상 사용할 수 없다는 오류 메시지를 남길 수 있습니다. 최종 버전에서는 코드 블록과 모든 메시지를 제거합니다.

이는 최종 사용자에게 경고없이 예기치 않은 기능을 식별하는 데 도움이 될 수 있습니다. 가장 좋은 시나리오에서 코드는 실제로 아무것도하지 않으며 필요한 모든 코드는 제거되기 전에 여러 버전으로 유지됩니다.


7
+1. 개발자 (또는 경영진)가 한 번에 모든 것을 던지려고하지 않고 프로젝트를 2 ~ 3 개의 안전한 단계로 나누려고한다면 피할 수있는 많은 버그와 고객 대면 문제를 보았습니다. 다음 프로젝트로 넘어 가기 전에 임의의 마감일.
ruakh

제목에 묻는 질문에 대한 답변이되지만 질문하면 제목이 잘못되었습니다. 제목은 코드를 삭제하는 방법을 묻지 만 본문은 코드를 삭제해도 안전한지 확인하는 방법에 관한 것입니다. 당신은 분명히 전자에 대답하지만, 그것이 OP가 실제로 요구 한 것이 확실하지 않습니다.
underscore_d

7

많은 사람들이 "안전한"할 일은 코드가 사용되지 않았다는 것을 증명할 수 없다면 코드를 그대로 두는 것입니다.

그러나 코드는 자산이 아니며 책임입니다.

중요한 이유를 설명하고 테스트를 지시하지 않는 한 "safer"대안은 삭제하는 것이 좋습니다.

여전히 확실하지 않은 경우 최소한 좀비 코드를 테스트하기위한 테스트를 추가해야합니다.


1 단계 : 모든 코드를 삭제합니다. 2 단계 : 필요한 것을 다시 넣습니다. 3 단계 : 반복하십시오.

1
@Adrian Knight Capital에 관심을 끌 수 있습니까? en.wikipedia.org/wiki/…- 참고로 포인트를 강화하려는 경우를 대비하여. 그것들은 기본적으로 일부 오래된 코드가 다시 생겨나 고 거의 5 억 달러를 잃어 버렸기 때문에 묵살되었습니다. 이어지는 문의는 릴리스 절차에 중점을 두었지만 핵심 문제는 "죽은 기능이 삭제되지 않았습니다"였습니다.
SusanW

6

기능 토글을 사용하여 해당 코드를 완전히 무시하도록 소프트웨어의 실행 경로를 변경할 수 있습니다.

이렇게하면 사용하지 않는 코드를 사용하여 변경 사항을 안전하게 배포하고 해제 할 수 있습니다. 코드와 관련된 주요 결함이 발견되면 토글을 다시 켜고 가능한 경로를 조사하십시오.

이 방법을 사용하면 오랜 시간 동안 문제가 발생하지 않고 배포없이 실시간으로 다시 켤 수있는 능력이있는 경우 자신감을 가질 수 있습니다. 그러나 더 나은 방법은 해당 영역 주위에 추가 로깅 및 테스트 적용 범위를 적용하여 사용 여부에 대한 더 많은 증거를 제공하는 것입니다.

토글에 대한 자세한 내용은 https://martinfowler.com/articles/feature-toggles.html을 참조 하십시오.


6

정적 분석은 물론 ... 새로운 도구는 필요하지 않습니다. 컴파일러에는 필요한 모든 정적 분석 도구가 있습니다.

그냥 방법 (예를 들면 변경의 이름 변경 DoSomething에를 DoSomethingX) 다음 빌드를 실행합니다.

만약 당신의 빌드가 성공한다면,이 방법은 어떤 것도 사용하지 않는 것입니다. 삭제해도 안전합니다.

빌드가 실패하면 코드를 호출하는 코드 라인을 분리 if하고 호출을 둘러싸는 명령문을 확인하여 트리거 방법을 결정하십시오. 트리거하는 가능한 데이터 유스 케이스를 찾을 수 없으면 안전하게 삭제할 수 있습니다.

실제로 코드를 삭제하는 것이 걱정된다면 코드를 유지하면서 ObsoleteAttribute (또는 해당 언어의 해당 속성)로 표시하십시오 . 한 버전에 대해 그런 식으로 릴리스 한 다음 문제가 없으면 코드를 제거하십시오.


8
이것은 완전한 동적 / 늦게 바인딩 이없는 프로그래밍 언어에 대한 조언입니다 . 그러나 가지고있는 사람들에게는 까다 롭습니다. 그리고 물론, 코드는 프로덕션에서 결코 사용되지 않더라도 메소드를 사용하고있을 수 있습니다.
eis

이 질문은 컴파일 타임 심볼 분석을 전제로합니다 ( 따라서 불필요한 것으로 보이는 코드를 찾았습니다. 컴파일러는 그것을 눈치 채지 못했습니다 ). 그리고 늦게 바인딩 된 함수 또는 객체조차 일반적으로 인터페이스 또는 맵 파일과 같은 두 위치에 정의되므로 빌드는 여전히 실패합니다.
John Wu

1
흠 .. 나는 흥미 롭다. 나는 당신이 말하는 것이 사실이라고 생각하지 않는다. 바닐라 자바 ​​스크립트 (미리 컴파일되지 않음), 루비, 파이썬 또는 스몰 토크가 아닙니다. 존재하지 않는 것을 참조하면 런타임시에만 오류가 발생합니다.
eis

어쩌면 우리는 물리적 바인딩에 대한 논리적 표현의 해상도 (예 : 주소에 대한 심볼)를 나타내는 "바인딩"이라는 의미에 동의하지 않을 수 있습니다. Javascript 함수는 포함하는 객체 내에 태그 / 값 쌍으로 저장되므로 바인딩 개념은 의미가 없습니다.
John Wu

1
예, 우리는 정말 동의하지 않습니다. 이 용어는 첫 번째 주석에서 설명한 것처럼 완전히 늦게 바인딩되지 않은 언어에서 다른 의미를 갖습니다. 런타임에 메소드 런타임을 추가하고 제거 할 수있는 언어로 런타임에 메소드를 바인드 할 때, 내가 이해하는 방식으로 늦은 바인딩을 사용하고 있습니다. 이것은 루비 / 파이썬 / 스몰 토크 스타일 언어에 해당되며 별도의 맵 파일이 없습니다. 특히 루비와 파이썬이 매우 널리 사용되기 때문에 "일반적으로"의 의미에 동의하지 않습니다.
eis

4
  • 코드 분석기를 사용하여 이것이 죽은 코드인지 확인합니다.
  • 테스트를 확인하고 코드에 도달하려고 시도했습니다. 테스트 케이스 내에서 코드에 도달 할 수 없으면 죽은 코드 일 수 있습니다.
  • 코드를 제거하고 대신 예외를 throw합니다. 한 릴리스에서는 예외가 활성화되고 두 번째 릴리스에서는 예외를 제거 할 수 있습니다. 안전을 위해 고객이 예외를 발견하면 원래 코드를 활성화 할 수 있도록 긴급 플래그 (Java에서 시스템 특성)를 배치하십시오. 따라서 프로덕션 환경에서 예외를 비활성화하고 원본 코드를 활성화 할 수 있습니다.

6
-1. 생산 코드, 안전 플래그를 변경하는 것은 절대 권장하지 않습니다. 문제의 코드가 사용되지 않은 것이 확실한 경우에만 생산 코드에서 제거해야합니다. 이런 종류의 혼란은 정확히 다른 생산 및 테스트 환경이 있어야하는 이유입니다.
Johannes Hahn

3
테스트 범위가 거의 90 % 일 때 환상적으로 작동하지만 그렇지 않은 경우 100.000 줄의 코드가있는 프로젝트가 있습니다. 그렇기 때문에 코드 테스트를 시도하고 코드에 도달 할 수있는 테스트가 없으면 죽었을 수 있습니다.
Markus Lausberg

IMHO 코드를 완전히 제거하지 못할 정도로 확실하지 않은 경우-프로덕션에서 예외를 발생시키지 않아야합니다. OP에서 제안한 로깅은 훨씬 더 나은 대안이며, 동일한 방식을 사용하며 불만을 제기하는 고객에게 의존하는 대신 진단을받을 수 있습니다.
Sebi

@JohannesHahn 프로덕션 환경에서 실행되는 코드 인 "프로덕션 코드"를 의미한다고 생각합니다.
jpmc26

@ jpmc26 물론입니다.
Johannes Hahn

3

도달 할 수없는 코드 제거

원칙적으로 정적으로 유형이 지정된 언어에서는 코드가 실제로 도달 가능한지 여부를 항상 알아야합니다. 코드를 제거하고 컴파일 할 수 있으며 오류가없는 경우 도달 할 수 없습니다.

불행하게도, 모든 언어가 정적으로 입력되는 것은 아니며 모든 정적으로 유형이 지정된 언어가 원칙적으로 정해지는 것은 아닙니다. 잘못 될 수있는 것은 (1) 반성 및 (2) 원치 않는 과부하입니다.

동적 언어 또는 충분히 강력한 리플렉션이있는 언어를 사용하여 조사중인 코드 조각을 리플렉션을 통해 런타임에 액세스 할 수있는 경우 컴파일러를 사용할 수 없습니다. 이러한 언어에는 Python, Ruby 또는 Java가 포함됩니다.

원칙적으로 과부하가 걸리지 않는 언어를 사용하는 경우 단순히 과부하를 제거하면 과부하 해결이 다른 과부하로 자동 전환 될 수 있습니다. 이러한 언어를 사용하면 코드 사용과 관련된 컴파일 타임 경고 / 오류를 프로그래밍 할 수 있습니다. 그렇지 않으면 컴파일러에 의존 할 수 없습니다. 이러한 언어에는 Java (use @Deprecated) 또는 C ++ (use [[deprecated]]또는 = delete)가 포함됩니다.

따라서 엄격한 언어로 작업하는 것이 운이 좋지 않으면 (Rust 염두에 두어야 함) 컴파일러를 신뢰하여 실제로 발을 쏠 수 있습니다. 불행히도 테스트 스위트는 일반적으로 불완전하므로 더 이상 도움이되지 않습니다.

다음 섹션 큐 ...


잠재적으로 사용되지 않는 코드 제거

더 많은 가능성이 코드가 실제로 참조, 그러나 당신은 의심 실제로 그것을 참조하는 코드의 분기가 취해지지 않습니다 것을.

이 경우 언어에 관계없이 코드에 도달 할 수 있으며 런타임 계측 만 사용할 수 있습니다.

과거에는 이러한 코드를 제거하기 위해 3 단계 접근 방식을 성공적으로 사용했습니다.

  1. 취하지 않을 것으로 의심되는 각 지점에서 경고를 기록하십시오.
  2. 한 사이클 후에 특정 코드를 입력 할 때 예외를 던지거나 오류를 반환하십시오.
  3. 다른주기 후에 코드를 삭제하십시오.

주기는 무엇입니까? 코드 사용주기입니다. 예를 들어, 금융 응용 프로그램의 경우 월간 짧은주기 (월말에 급여가 지급됨)와 긴주기는 예상됩니다. 이 경우 연말 재고가 달리 사용되지 않는 코드 경로를 사용할 수 있다는 경고가 발생하지 않는지 확인하기 위해 최소 1 년을 기다려야합니다.

바라건대, 대부분의 응용 프로그램은 더 짧은주기를 갖습니다.

TODO 의견을 날짜와 함께 다음 단계로 넘어갈 때 조언하는 것이 좋습니다. 그리고 당신의 달력에서 알림.


1
실제로 C ++에서는 [[deprecated]]해당 버전을 호출하는 사이트를 식별하도록 의심스러운 과부하를 표시 할 수 있습니다 . 그런 다음 검사하여 동작이 변경되는지 확인할 수 있습니다. 또는 과부하를 다음과 같이 정의하십시오 = delete.이 경우 다른 버전 중 하나를 사용하려면 인수를 명시 적으로 캐스팅해야합니다.
Toby Speight

@TobySpeight : 맞습니다. 그리고 좋은 대안이기도합니다. 그것을 편집하겠습니다.
Matthieu M.

"의사, 내가 이렇게하면 아파요." " 그렇게하지 마라! "코드를 관리 할 수 ​​없게 만드는 접근 방식을 사용하지 마십시오.

2

프로덕션에서 코드를 제거하는 것은 집 청소와 같습니다. 다락방에서 물건을 버리는 순간 다음날 아내는 1923 년에 사망 한 이웃으로부터 증조 할머니의 세 번째 조카의 귀향 선물을 버리기 위해 다음 날 당신을 죽일 것입니다.

진지하게, 모든 사람들이 이미 언급 한 다양한 도구를 사용하여 커서 분석을 한 후, 이미 언급 된 단계적 사용 중단 접근법을 사용한 후에는 실제 제거가 수행 될 때 회사에서 퇴출 될 수 있음을 명심하십시오. 코드를 유지하고 실행을 기록하게하고 실행에 대한 경고가 반드시 귀하 (또는 후임자와 할당)에게 전달되도록하는 것이 필수적입니다.

이 방법을 따르지 않으면 아내가 살해 당할 가능성이 있습니다. 모든 유품과 같이 코드를 유지하면 무어의 법칙이 구조에 온다는 사실과 "내 신발 속의 바위"처럼 느껴지는 코드에 사용되는 정크 디스크 공간의 비용으로 양심을 쉴 수 있습니다. 그리고 당신은 복도에서 여러 개의 물 냉각기 험담과 이상한 외모의 중심이 될 위험이 없습니다.

추신 : 의견에 대한 답변으로 명확히하기 위해. 원래의 질문은 "당신은 어떻게 안전하게 삭제 합니까? "입니다. 물론, 내 대답에는 Version Control이 있다고 가정합니다. 쓰레기를 파서 마치 귀중한 것을 찾는 것처럼 가정합니다. 어떤 의미로든 코드를 버릴 수있는 기관은 없으며 모든 개발자가 엄격하게 코드를 관리해야합니다.

문제는 불필요한 코드에 관한 것입니다. 실행 경로의 100 %가 도달하지 않는다고 보장 할 수 없다면 코드 조각이 불필요하다는 것을 결코 알 수 없습니다. 그리고 이것은 이것이 보장 할 수 없을만큼 충분히 큰 소프트웨어라고 가정합니다. 그리고 질문을 잘못 읽지 않는 한이 대화의 전체 스레드와 관련된 유일한 시간은 제거 된 코드가 호출되어 런타임 / 생산 문제가있는 생산 중입니다. 버전 관리는 생산 실패로 인해 누군가의 배후를 저장하지 않으므로 "버전 제어"에 대한 의견은 질문이나 원래의 요점과 관련이 없습니다.

IMHO의 의견은 불필요하며 삭제 후보입니다.


12
내가 버전 관리에 해당하는 경우 아내의 이의 제기는 쉽게 취소됩니다. 따라서 코드를 삭제하면 죽이는 범죄가 아닙니다. 저장소는 절대 버리지 않습니다 .
JDługosz

Object Oriented 프로그래밍은 메소드를 호출 할 수있는 범위를 좁히기로되어 있다고 생각했습니다. 따라서보다 쉽게 ​​이해하고 관리 할 수있는 코드로 이어져야합니다. 그렇지 않으면 왜 그렇게 하는가?

@nocomprende이 글의 어느 곳에서도 논의가 OOP 디자인 / 언어에만 국한되는 것은 아니라고 지적했다. 왜 그것이 관련이 있다고 생각하는지 모르겠습니다.
underscore_d

1

어쩌면 컴파일러 눈치 채지 않을 것입니다.

크기에 맞게 전체 컴파일러 최적화로 빌드를 실행하십시오. 그런 다음 의심스러운 코드를 삭제하고 빌드를 다시 실행하십시오.

이진을 비교하십시오. 그것들이 동일하다면, 컴파일러는 코드를 알아 차리고 자동으로 삭제했습니다. 소스에서 안전하게 삭제할 수 있습니다.

바이너리가 다르면 결정적이지 않습니다. 다른 변화 일 수도 있습니다. 일부 컴파일러에는 바이너리에 컴파일 날짜 및 시간이 포함되어있을 수도 있습니다 (아마도 구성 가능).


1
모든 언어가 컴파일되는 것은 아니며 모든 컴파일러에 최적화가있는 것은 아니며 모든 최적화가 동일한 것은 아니며, 많은 이유로 인해 코드가 존재하는 경우에만 호출되지 않은 코드를 제거하지 않습니다. 코드가 공유 라이브러리 / DLL에 있으면 삭제되지 않습니다.
Steve Barnes

1
@SteveBarnes 그래, LTO를하지 않고 모든 것을 정적으로 연결하지 않는다면 약간의 고통이 따른다. 그것은 주어진 것입니다.
Navin

1

저는 최근에 "deleteFoo"라는 방법으로이 정확한 상황을 접했습니다. 전체 코드베이스에서 메소드 선언 이외의 문자열이 발견되지는 않았지만 메소드 상단에 로그 줄을 작성하는 것이 현명합니다.

PHP :

public function deleteFoo()
{
    error_log("In deleteFoo()", 3, "/path/to/log");
}

코드가 사용 된 것으로 나타났습니다! 일부 AJAX 메소드는 "method : delete, elem = Foo"를 호출 한 다음 call_user_func_array () 로 연결하여 호출 합니다.

확실하지 않은 경우 로그하십시오! 로그가 채워지지 않은 채 충분한 시간을 보냈다면 코드 제거를 고려하십시오. 그러나 코드를 제거하더라도 로그를 유지하고 날짜를 적어두고 Git에서 커밋을 쉽게 찾을 수 있도록하십시오!


Tombstone (php : github.com/scheb/tombstone ) 이라는 PHP 및 Perl 라이브러리가 여기에 유용 할 수 있습니다.
Alister Bulman

0

grep먼저 사용 가능한 도구를 사용 하거나 코드에 대한 참조를 찾을 수 있습니다. (원래 나의 지시 / 조언이 아닙니다.)

그런 다음 코드를 제거 할 위험이 있는지 또는 내 제안을 사용할 수 있는지 결정하십시오.

함수 / 코드 블록을 수정하여 로그 파일에 사용되었음을 기록 할 수 있습니다. 이러한 메시지가 로그 파일에 "기록되지 않은"경우 로깅 코드를 제거 할 수 있습니다.

두 가지 문제 :

  1. 다른 사용자로부터 로그 가져 오기 아마도 종료시 프로그램을 중단시키고 사용자에게 오류 로그를 보내달라고 요청하는 전역 플래그를 설정할 수 있습니다.

  2. 발신자를 추적합니다. 일부 고급 언어 (예 : Python)에서는 쉽게 역 추적을 얻을 수 있습니다. 그러나 컴파일 된 언어에서는 리턴 주소를 로그에 저장하고 종료시 코어 덤프를 강제 실행해야합니다 (포인트 1).
    C에서는 매우 간단해야합니다. 조건부 블록 (예 : #ifdef ... #endif)을 사용하면 작동한다는 것을 알았을 때만이를 사용하고 (반드시이를 테스트 한 경우) 리턴 주소를 읽으십시오. 스택에서 (인라인 어셈블리 언어가 필요할 수도 있고 필요하지 않을 수도 있음).

로그 파일에 인수를 저장하면 유용하거나 유용하지 않을 수 있습니다.


0

주변 코드가 무엇인지 아는 경우 테스트 하여 코드가 깨져 있는지 확인하십시오. 이것은 작업하는 코드를 리팩토링하는 가장 간단하고 비용 효율적인 방법이며, 작업중인 코드의 변경 사항을 개발할 때 먼저 수행해야합니다.

반면에 코드가 무엇인지 모르는 부분을 ​​리팩토링하는 경우 제거하지 마십시오 . 먼저 이해 한 다음 안전하다고 판단되면 리팩토링하십시오 (리팩토링이 시간을 올바르게 사용한다고 결정할 수있는 경우에만).

이제 '죽은'코드가 실제로 아무 것도 연결되어 있지 않은 상황이있을 수 있습니다 (내가 직접 봤다는 것을 알고 있습니다) . 계약자가 개발 한 코드 라이브러리와 같이 앱이 제공 된 직후에 사용되지 않아 실제로 구현되지 않은 코드 라이브러리와 같은 이유는 무엇입니까? (예, 구체적인 예가 있습니다. 어떻게 알았습니까?)

나는 개인적 으로이 코드를 모두 없애 버렸지 만이 변경이 잠재적으로 영향을 줄 수 있는 코드의 양에 따라 (당신이 뭔가 간과했을 가능성이 항상 있기 때문에) 가볍게 복용하지 않는 것이 위험입니다. 이 고대 레거시 코드를 제거하면 응용 프로그램이 중단되는지 확인하기 위해 매우 신중하고 공격적인 단위 테스트를 실행해야합니다.

이제 모든 것을 말하면, 그런 코드를 제거하려고 시도하는 시간이나 정신이 가치 가 없을 것입니다. 응용 프로그램에 심각한 문제가되지 않는 한 (예 : 응용 프로그램 팽창으로 인해 보안 검색을 완료 할 수없는 이유는 무엇입니까? 왜 그래도 예제가 있습니까?) 그렇지 않으면 권장하지 않습니다. 그러한 상황에서 코드가 실제로 썩기 시작했습니다.

간단히 말해-코드의 기능을 알고 있다면 먼저 테스트하십시오. 그렇지 않으면 아마 그대로 둘 수 있습니다. 당신은 당신이 알고있는 경우에 할 수없는 혼자두고, 변경 사항을 구현하기 전에 적극적으로 변화를 테스트하는 시간을 바칩니다.


0

이 경우 항상 업계 표준이라고 생각한 나의 접근 방식은 이상하게도 언급되지 않았습니다.

두 번째 눈을 얻으십시오.

"사용되지 않는 코드"에는 여러 종류가 있으며 어떤 경우에는 삭제가 적절하고, 다른 경우에는 리팩토링해야하며, 다른 경우에는 가능한 한 멀리 돌아가서 다시 돌아 보지 않아도됩니다. 당신은 그것이 어느 것인지 알아 내야하며, 그렇게하려면 두 번째 경험이있는 사람과 가장 잘 어울립니다! -개발자, 코드베이스에 매우 익숙한 개발자. 이를 통해 불필요한 실수의 위험을 크게 줄이고 코드베이스를 유지 관리 가능한 상태로 유지하기 위해 필요한 개선 작업을 수행 할 수 있습니다. 이 작업을 수행하지 않으면 코드베이스에 대해 잘 알고있는 개발자가 부족할 수 있습니다.

로깅 접근법도 보았습니다. 더 정확하게 말하자면 로깅 코드를 보았습니다 .10 년 동안 더 많은 죽은 코드가 남아 있습니다. 로깅 기능은 전체 기능을 제거하는 것에 대해 이야기하고 있지만 작은 데드 코드를 제거하는 것은 아닙니다.


0

질문에 대한 간단한 대답은 이해하지 못하는 코드를 안전하게 삭제할 수 없다는 것입니다. 여기에는 코드가 어떻게 호출되는지 이해하지 못하는 것이 포함됩니다. 약간의 위험이 있습니다.

피할 수없는 위험을 완화하는 최선의 방법을 판단해야합니다. 다른 사람들은 로깅에 대해 언급했습니다. 물론 로깅은 사용되었음을 증명할 수 있지만 그렇지 않다는 것을 증명할 수는 없습니다. 데드 코드의 주요 문제점은 유지 보수된다는 것이므로, 데드 코드로 의심되는 내용을 추가하지 않고 주석을 추가하지 않아도됩니다.

코드가 소스 제어하에있는 경우 언제든지 코드가 추가 된시기를 확인한 후 호출 방법을 결정할 수 있습니다.

궁극적으로, 당신은 그것을 이해하거나 홀로 남겨 두거나 기회를 얻습니다.


0

문제의 코드 개발자가 여전히 사용 가능한 경우 코드 제거를 검토하십시오 . 또한 코드에서 주석을 읽으십시오 .

적절한 설명,이 코드가 추가 된 이유 및 어떤 기능을 제공하는지 알 수 있습니다. 특정 사용 사례를 쉽게 지원할 수 있거나 실제로 필요하지 않은지 판단 할 충분한 전문 지식이 없을 수도 있습니다. 극단적 인 경우, C 프로그램에서 사용 가능한 모든 명령문을 제거하고 문제점을 발견하지 못할 수 있습니다 (메모리가 부족하면 몇 분이 걸릴 수 있음).

코드 작성자가 당신 옆에 앉아 있으면 정말 나쁜 문화이지만, 그가 잘못된 코드를 작성한다는 확신이 있기 때문에 말할 이유가 없습니다. 물론 그는 주석에 임의의 단어를 쓰므로 시간을 낭비하지 않아도됩니다.

코드에 주석을 작성하는 가장 중요한 이유 중 하나는 왜 이런 식으로 구현되었는지 설명하는 것입니다. 솔루션에 동의하지 않을 수도 있지만 문제를 고려해야합니다.

저자와의 토론은 또한 코드가 제거되었거나 완료되지 않은 것의 역사적 잔재이므로 삭제해도 안전하다는 것을 알 수 있습니다.


-1

Markus Lausberg의 첫 번째 요점에 강력하게 동의합니다. 도구를 사용하여 코드를 분석해야합니다. 원숭이 뇌는 이런 종류의 임무를 신뢰해서는 안됩니다 !!

대부분의 표준 프로그래밍 언어는 IDE 및 "모든 사용에 대한 찾기"기능을 갖춘 IDE 및 모든 종류의 IDE에 사용될 수 있습니다.이 기능은 이러한 상황에 적합한 도구입니다. (예를 들어 Eclipse의 Ctrl + Shift + G)

물론 : 정적 분석기 도구는 완벽하지 않습니다. 문제의 메소드가 호출되는 결정이 런타임시에만 발생하고 더 빨리 발생하지 않는보다 복잡한 상황을 알고 있어야합니다 (Reflection을 통한 호출, 스크립팅 언어의 "eval"함수 호출 등).


5
아마도 원숭이 뇌가 코드를 작성해서는 안됩니까? " 인간의 손길이 닿지 않은 "은 마케팅 문구였습니다. 나는 항상 고릴라 손이 그 일을하는 것을 상상했다.

3
(! 쉿 당신은 이야기를 망칠거야!) (원숭이 뇌도 도구를 썼다)

1
둘 다 내 요점을 놓친 것 같아 나는 정적 코드 분석이 메소드 또는 클래스의 모든 호출을 찾을 것이라는 보장은 없다고 분명히 말했다. 주석에 표시된 것처럼 정적 분석입니다. 리플렉션, eval () 등을 통해 동적 호출을 찾을 수 없으며 기대할 수 없습니다. 내 요점은 정적 코드 분석이 코드 조각을 삭제하는 데 필요한 전제 조건으로 간주되어야한다는 것입니다. 그리고 프로젝트가 클수록 인간의 두뇌가 정확하게 분석하지 않고 분석을 수행 할 가능성도 줄어 듭니다.
Johannes Hahn

1
... 정적 코드 분석은 컴퓨터에서 가장 잘 수행되는 지루하고 반복적 인 작업입니다. 컴퓨터가 확실하게 실행할 수 있지만 유인원 뇌에 의해 실행될 때 믿을 수없는 종류의 작업. 후자는 까다로운 반사와 평가 호출을 찾는 것처럼 컴퓨터가 할 수없는 일에만 사용해야합니다.
Johannes Hahn

1
다시 한 번 요점을 놓쳤다. 이 도구는 유인원 두뇌에 의해 작성 되었기 때문에 완벽하지는 않지만 (정확한 호출 계층 구조를 계산하는 것이 그리 어렵지는 않습니다), 여전히 수동 작업 실행보다 훨씬 우수합니다. 이것은 전혀 또는 전혀 다른 상황이 아닙니다. 99 % 신뢰할 수있는 도구는 99 % 퍼센트로 시작하지만 코드의 첫 줄 이후에 훨씬 더 낮은 속도로 빠르게 떨어지는 두뇌보다 여전히 선호됩니다.
Johannes Hahn

-1

두 가지 가능성 :

  1. 99 % 이상의 테스트 범위가 있습니다 . 코드를 삭제하고 완료하십시오.
  2. 신뢰할 수있는 테스트 적용 범위가 없습니다. 그에 대한 답변은 지원 중단 경고 를 추가하는 것 입니다. 즉, 제정신을 수행하는 코드를 해당 위치에 추가합니다 (예 : 응용 프로그램의 일상적인 사용과 충돌하지 않는 쉽게 볼 수있는 위치에 경고를 기록). 그런 다음 몇 개월 / 년 동안 끓으십시오. 해당 항목이 발견되지 않은 경우 사용 중단을 예외를 발생시키는 것으로 대체하십시오. 잠시 기다려주세요. 마지막으로 모든 것을 완전히 제거하십시오.

2
이것은 이전 17 답변에서 제시되고 설명 된 점에 비해 실질적인 것을 제공하지 않는 것 같습니다. 적용 범위와 사용 중단 경고에 대해서는 이미 논의되었습니다
gnat

@ gnat, 당신이 맞아요. 처음에 답을 스캔했을 때 어떤 이유로 나는 상단에 짧고 간결 하게이 두 가지 지점에 도달하지 않는 몇 가지를 보았습니다. 대답 중간에 그런 것이 있습니다.
AnoE
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.