소개
레거시 코드 중 일부를 읽는 동안 코드 중복과 함수 구성 부족으로 짜증이 났습니다. 올해 CI 파이프 라인에서 많은 작업을 해왔기 때문에 새 클론이 도입되면 커밋을 빨간색으로 표시하여 클론이 마스터 브랜치에 들어가는 것을 금지 할 수 있는지 확인하고 싶었습니다.
정의
이 섹션은 LimeSurvey 코드 품질 가이드에서 복사되었습니다.
연구자들이 정의한 네 가지 주요 유형의 코드 클론이 있습니다.
편집 거리는 두 복제물을 동일하게 만들기 위해 필요한 변경 횟수로 볼 수 있습니다. 이러한 변경 사항은 공백이나 변수 이름이 아닌 토큰에 관한 것입니다.
거짓 양성은 알고리즘에 의해 탐지 된 클론이며 실제로는 클론이 아닙니다. 거짓 음성은 코드베이스에 클론이 존재하지만 알고리즘이 이를 감지 할 수없는 반대입니다. 둘 다 가능한 한 많이 줄여야 합니다.
일부 보고서는 코드 클론이 변경 가능성에 해롭지 않거나 해로운 것으로 입증 될 수 없다는 그림을 그립니다 (“코드 클론이 중요합니까?”참조).
도구
많은 (모두?) 빅 코드 분석 도구에는 Scrutinizer 또는 SonarQube와 같은 코드 중복 감지도 포함됩니다. 다음과 같은 작은 도구도 있습니다.
Scrutinizer와 SonarQube에서 어떤 알고리즘을 사용하는지 알 수 없었지만 phpcpd와 jscpd는 모두 Rabin-Karp 알고리즘을 사용합니다. 빠른 알고리즘이지만 유형 1 및 유형 2 클론 만 감지 할 수 있습니다. 더 큰 도구로만 코드 복제를 탐색하는 데 어려움을 겪었습니다.
예
특히 저를 괴롭히는 예를 들어 보겠습니다 (다른 코드 품질 문제는 무시).
if (\PHP_VERSION_ID < 80000) {
$bOldEntityLoaderState = libxml_disable_entity_loader(true);
}
$sQuestionConfigFilePath = App()->getConfig('rootdir') . DIRECTORY_SEPARATOR . $pathToXML . DIRECTORY_SEPARATOR . 'config.xml';
if (!file_exists($sQuestionConfigFilePath)) {
throw new Exception(gT('Extension configuration file is not valid or missing.'));
}
$sQuestionConfigFile = file_get_contents($sQuestionConfigFilePath);
이 스니펫에는 중간 선이 약간 다른 중복이 있습니다.
$sQuestionConfigFilePath = App()->getConfig('rootdir') . DIRECTORY_SEPARATOR . $sConfigPath;
변경된 줄 앞과 뒤의 줄이 모두 너무 작아서 유형 2 복제로 보고 할 수 없습니다. 필요한 것은 작은 변화를 처리하는 알고리즘입니다.
ConQAT
ConQAT는 복제를 포함하여 코드 기반의 다양한 측면을 분석하는 오픈 소스 도구였습니다. 이제 수명이 다되었습니다. 그들은 훌륭한 논문을 썼습니다. Do Code Clones Matter? 평가 프로젝트를 포함한 알고리즘의 기본 사항을 설명하는 (PDF). Rabin-Karp과 마찬가지로 토큰 기반이지만 비교시 해시 대신 접미사 트리를 사용하므로 비교할 때 편집 거리를 구성 할 수 있습니다. 평등 대신 유사성으로 비교합니다.
이 알고리즘은 Java로 코딩 된 Apache 2.0 라이선스에 따라 오픈 소스로 출시되었습니다.
Porting
우리는 Java를 사내에서 사용하지 않고 PHP 만 사용하므로 Unix 철학에서 좋은 CLI 도구를 원했습니다. 한 가지만 수행하십시오. phpcpd도 jscpd도 Type 3 클론을 감지 할 수 없기 때문에 알고리즘을 약 2k LoC 인 PHP로 이식하기로 결정했습니다. 대부분은 이미 완료되었습니다. PR은 여기에서 작업 중이며 원하는 경우 복제 (말장난 없이)하고 로컬에서 실행할 수 있습니다.
평가
결국 그만한 가치가 있었습니까? 우리의 코드 기반에는 훨씬 빠른 해시 알고리즘에 비해 새로운 알고리즘의 느린 실행 시간에 동기를 부여하기에 충분한 유형 3 클론이 포함되어 있습니까? 그리고 그 클론에 결함이 있습니까? 모르겠어요. 지금까지 중간 선이 변경된 위의 예는 흔하지 않은 것 같습니다. 종종 Type 3 클론은 두 개의 더 작은 Type 2 클론으로 식별 할 수 있습니다. 하지만 새 알고리즘은 더 정확하며 작은 토큰 변경에도 멈추지 않고 전체 클론을 더 자주 감지합니다. 알고리즘을 올바르게 조정하는 것도 문제입니다. 오탐이 너무 많으면 모두가 짜증을 낼 것입니다.
CI에 통합하는 방법에 대해 아직도 고민 중입니다. 첫 번째 단계는 각 파일에 대해 개별적으로 알고리즘을 실행하는 단일 파일 분석이라고 생각합니다. 이렇게 하면 특히 레거시 코드를 사용하는 경우 단일 클래스가 전체 프로젝트보다 더 나은 요소가 될 수 있다고 가정하여 알고리즘을 더 민감하게 조정할 수 있습니다. 그러면 프로젝트 전체에서 더 빠른 알고리즘을 사용할 수 있습니다.
등록된 댓글이 없습니다.