큰 파일의 리팩토링을 처리하는 가장 좋은 방법은 무엇입니까?


41

나는 불행히도 소프트웨어 품질 지침이 항상 따르지 않는 일부 파일이있는 더 큰 프로젝트를 진행하고 있습니다. 여기에는 여러 가지 고유 한 기능이 포함 된 큰 파일 (2000-4000 줄 읽기)이 포함됩니다.

이제이 큰 파일을 여러 개의 작은 파일로 리팩토링하려고합니다. 문제는 이들이 너무 커서 여러 지점의 여러 사람 (포함)이이 파일을 작업하고 있다는 것입니다. 따라서 이러한 리팩토링을 다른 사람들의 변경 사항과 병합하는 것이 어려워지기 때문에 개발 및 리팩터링에서 실제로 분기 할 수 없습니다.

물론 모든 사람이 파일을 개발, "고정"(즉, 더 이상 편집 할 수 없도록), 리팩토링 및 "고정 해제"하기 위해 다시 병합하도록 요구할 수 있습니다. 그러나 이것은 리팩토링이 완료 될 때까지 모든 사람들이 기본적 으로이 파일에 대한 작업을 중지해야하기 때문에 실제로는 좋지 않습니다.

리팩토링하는 방법이 있습니까? 다른 사람이 작업을 중단 (오래 오랫동안)하거나 기능 분기를 병합하여 개발하도록 요구하지 않습니까?


6
나는 이것이 사용되는 프로그래밍 언어에 달려 있다고 생각합니다.
Robert Andrzejuk

8
나는 "작은 증분"체크인을 좋아한다. 누군가 레포의 사본을 최신 상태로 유지하지 않는 한,이 방법은 모든 사람의 병합 충돌을 최소화합니다.
Matt Raffel

5
시험은 어떻게 생겼습니까? 큰 (그리고 아마도 중요한!) 코드 조각을 리팩터링하려는 경우 리팩토링하기 전에 테스트 스위트가 실제로 양호한 상태인지 확인하십시오. 이렇게하면 작은 파일로 올바르게 만들 수 있습니다.
corsiKa

1
이 방법으로 취할 수있는 수많은 방법이 있으며 최선의 방법은 상황에 따라 다릅니다.
스티븐

3
나는 가장 큰 파일이 10k 줄 길이의 프로젝트에 참여했으며 그 자체로는 6k 줄 길이의 클래스가 포함되어 있으며 모두가 그것을 두려워합니다. 내 말은 당신의 질문이 훌륭하다는 것입니다. 우리는 심지어이 단일 클래스가 마우스에서 스크롤 휠을 잠금 해제해야하는 좋은 이유라는 농담을 발명했습니다.
ElmoVanKielmo

답변:


41

이것은 사회적 문제만큼 기술적이지 않다는 것을 올바르게 이해했습니다. 과도한 병합 충돌을 피하려면 팀은 이러한 충돌을 피하는 방식으로 협업해야합니다.

분기가 매우 쉽지만 병합하는 데 여전히 많은 노력이 필요하다는 점에서 Git의 큰 문제 중 하나입니다. 개발 팀은 많은 브랜치를 시작하는 경향이 있으며 컨텍스트를 이해하지 않고 Git Flow를 모방하려고하기 때문에 병합하기가 어렵다는 것에 놀랐습니다.

빠르고 쉬운 병합의 일반적인 규칙은 큰 차이가 누적되는 것을 방지하는 것입니다. 특히 기능 분기의 수명이 매우 짧아야합니다 (몇 달이 아니라 몇 시간 또는 몇 일). 변경 사항을 신속하게 통합 할 수있는 개발 팀은 병합 충돌이 줄어 듭니다. 일부 코드가 아직 생산 준비가되지 않은 경우 통합 할 수 있지만 기능 플래그를 통해 비활성화 할 수 있습니다. 코드가 마스터 브랜치에 통합 되 자마자 원하는 리팩토링에 액세스 할 수있게됩니다.

그것은 당신의 즉각적인 문제에 너무 많은 것일 수 있습니다. 그러나 리팩토링을 수행 할 수 있도록 동료에게이 파일에 영향을 미치는 변경 사항을 병합하도록 요청하는 것이 가능할 수 있습니다. 더 오래 기다리면 병합 충돌 자체를 처리해야합니다. 그것은 불가능하지 않으며 단지 피할 수있는 일입니다.

또한 많은 양의 종속 코드가 손상되는 것을 막고 API 호환 변경 만 할 수 있습니다. 예를 들어, 일부 기능을 별도의 모듈로 추출하려는 경우 :

  1. 기능을 별도의 모듈로 추출하십시오.
  2. 이전 함수를 변경하여 호출을 새 API로 전달하십시오.
  3. 시간이 지남에 따라 포트 종속 코드가 새 API로 전달됩니다.
  4. 마지막으로 이전 기능을 삭제할 수 있습니다.
  5. (다음 기능들을 반복한다)

이 다단계 프로세스는 많은 병합 충돌을 피할 수 있습니다. 특히 다른 사람이 추출한 기능을 변경하는 경우에만 충돌이 발생합니다. 이 접근법의 비용은 모든 것을 한 번에 변경하는 것보다 훨씬 느리고 일시적으로 두 개의 중복 API가 있다는 것입니다. 급한 일이이 리팩토링을 방해하고 복제가 잊혀지거나 우선 순위가 낮아질 때까지는 그렇게 나쁘지 않습니다.

그러나 결국 모든 솔루션을 사용하려면 팀과 협력해야합니다.


1
@Laiv 불행히도 그것은 매우 일반적인 조언이지만 Continuous Integration과 같은 민첩한 공간에서 나온 아이디어는 분명히 장점이 있습니다. 함께 일하고 자주 업무를 통합하는 팀은 서로 만 협력하는 팀보다 교차 간 큰 변경 작업을보다 쉽게 ​​수행 할 수 있습니다. 이것은 반드시 SDLC에 관한 것이 아니라 팀 내의 협업에 관한 것입니다. 일부 접근 방식은 함께 실행하는 것이 더 실현 가능해 지지만 (Open / Closed Principle, 마이크로 서비스 생각) OP 팀은 아직 없습니다.
amon

22
기능 브랜치의 수명이 짧아야한다는 것은 말할 필요도 없습니다. 단지 오랜 기간 동안 상위 브랜치에서 분기되지 않아야합니다. 상위 브랜치에서 피쳐 브랜치로 변경 사항을 정기적으로 병합하면 피쳐 브랜치가 더 오래 붙어야하는 경우에 작동합니다. 그래도 기능 분기를 더 이상 필요 이상으로 유지하지 않는 것이 좋습니다.
Dan Lyons

1
@Laiv 내 경험상, 사전 리팩토링 디자인을 팀과 미리 논의하는 것이 합리적이지만 한 사람이 코드를 변경하는 것이 가장 쉽습니다. 그렇지 않으면, 당신은 물건을 병합 해야하는 문제로 돌아갑니다. 4k 라인은 많이 들리지만 실제로 extract-class 와 같은 대상 리팩터링 에는 적합하지 않습니다 . 마틴 파울러의 리팩토링 책을 읽어 본다면 여기에서 너무 힘들다. 그러나 4k 라인 “이 기능을 어떻게 개선 할 수 있는지 보자”와 같은 타겟이없는 리팩토링 에만 적용된다 .
amon

1
@DanLyons 원칙적으로 당신은 맞습니다 : 그것은 병합 노력의 일부를 퍼뜨릴 수 있습니다. 실제로 Git의 병합은 병합 되는 지점 의 최신 공통 조상 커밋에 크게 좌우 됩니다. 마스터 → 피처를 병합한다고해서 마스터에 대한 새로운 공통 조상을 얻을 수는 없지만 기능 → 마스터를 병합하면됩니다. 반복되는 master → feature merge를 사용하면 동일한 충돌을 반복해서 해결해야 할 수 있습니다 (그러나이를 자동화하려면 git rerere 참조). 마스터의 팁이 새로운 공통 조상이 되었기 때문에 리베이스는 엄청나게 뛰어나지 만 역사 재 작성에는 다른 문제가 있습니다.
amon

1
git에 대한 분노를 제외하고는 분기하기가 너무 쉬워서 분기가 너무 자주 발생합니다. SVN과 CVS의 시대는 사람들이 모든 관련 문제와 함께 가능한 경우 일반적으로 피할 수 없을 정도로 힘들거나 번거 로웠을 때를 기억합니다. 분산 시스템 인 git에서 많은 분기를 갖는 것은 실제로 많은 개별 저장소를 갖는 것 (즉, 각 개발자)과 다르지 않습니다. 솔루션은 다른 곳에 있으며 분기하기 쉬운 것이 문제가 아닙니다. (그리고 예, 나는 그것이 제쳐두고 있음을 알지만 여전히 그렇습니다).
AnoE

30

더 작은 단계로 리팩토링을 수행하십시오. 큰 파일 이름이 있다고 가정 해 봅시다 Foo.

  1. 비어있는 새 파일을 추가하고 Bar"trunk"에 커밋하십시오.

  2. Foo로 이동할 수있는 코드의 작은 부분을 찾으십시오 Bar. 이동을 적용하고, 트렁크에서 업데이트하고, 코드를 빌드 및 테스트하고, "트렁크"에 커밋하십시오.

  3. 2 단계를 반복 할 때까지 FooBar같은 크기를 가지고 (또는 당신이 선호하는 어떤 크기)

이렇게하면 다음 번에 팀원이 트렁크에서 분기를 업데이트 할 때 "작은 부분"으로 변경 사항을 가져와 하나씩 병합 할 수 있으므로 한 번에 전체 분할을 병합하는 것보다 훨씬 쉽습니다. 다른 사람이 사이에 트렁크를 업데이트했기 때문에 2 단계에서 병합 충돌이 발생할 때도 마찬가지입니다.

이렇게하면 병합 충돌이나 수동으로 해결할 필요가 없지만 각 충돌을 작은 코드 영역으로 제한하여 관리하기가 더 쉽습니다.

물론 팀에서 리팩토링을 전달하십시오. 동료에게 자신이하고있는 일을 알려 주면 특정 파일에 대해 병합 충돌이 필요한 이유를 알 수 있습니다.


2
이것은 rerere
gits

@ D. BenKnoble : 그 추가에 감사드립니다. 나는 git 전문가가 아니라는 것을 인정해야한다 (그러나 설명 된 문제는 git에 특별히 적용되지 않으며 분기를 허용하는 모든 VCS에 적용되며 내 대답은 대부분의 시스템에 적합해야 함).
Doc Brown

나는 그 용어를 기초로 생각했다. 실제로 git을 사용하면 이러한 종류의 병합은 여전히 ​​한 번만 수행됩니다 (단 하나만 끌어서 병합하는 경우). 그러나 개발자의 선호에 따라 항상 커밋을 따거나 개별 커밋을 병합하거나 리베이스 할 수 있습니다. 시간이 더 걸리지 만 자동 병합이 실패 할 가능성이있는 경우 확실히 가능합니다.
D. Ben Knoble

18

파일을 원자 작업으로 분할하려고 생각하지만 중간에 변경할 수 있습니다. 파일은 시간이 지남에 따라 점차 커지고 시간이 지남에 따라 점차 작아 질 수 있습니다.

오랜 시간 동안 변경되지 않은 부분을 선택하고 (이를 git blame도울 수 있음) 먼저 분리하십시오. 변경 사항을 모든 사람의 지사에 병합 한 다음 나눌 가장 쉬운 부분을 선택하십시오. 어쩌면 한 부분을 분할하는 것이 너무 큰 단계 일 수 있으므로 큰 파일 내에서 먼저 재 배열해야합니다.

사람들이 개발을 위해 자주 합병하지 않는다면, 그들이 합병 한 후에 그들이 변경 한 부분을 분리 할 수있는 기회를 가지도록 격려해야합니다. 또는 풀 요청 검토의 일부로 분할을 수행하도록 요청하십시오.

아이디어는 천천히 목표를 향해 나아가는 것입니다. 진행 속도가 느리다는 느낌이 들지만 갑자기 코드가 훨씬 우수하다는 것을 알게 될 것입니다. 해저 라이너를 돌리는 데 시간이 오래 걸립니다.


파일이 크게 시작되었을 수 있습니다. 크기가 큰 파일을 빠르게 만들 수 있습니다. 나는 하루 또는 주에 1000의 LoC를 쓸 수있는 사람들을 알고 있습니다. 그리고 OP는 자동화 된 테스트에 대해서는 언급하지 않았는데, 이는 테스트가 부족하다는 것을 나타냅니다.
ChuckCottrill

9

이 문제에 대한 일반적인 해결책과 다른 해결책을 제안합니다.

이것을 팀 코드 이벤트로 사용하십시오. 모든 사람이 코드를 체크인 할 수 있도록하고 파일 작업을 계속하고있는 다른 사람을 도와주십시오. 관련자 모두가 코드를 체크인하면 프로젝터가있는 회의실을 찾고 함께 작업하여 새로운 파일로 이동합니다.

이것에 특정 시간을 설정하여 끝이 보이지 않는 일주일 분량의 논쟁이되지 않도록 할 수 있습니다. 대신, 일주일에 1-2 시간 정도의 이벤트 일 수도 있습니다. 파일을 리팩터링하는 데 1-2 시간 만 필요할 수도 있습니다. 시도하기 전까지는 알 수 없습니다.

이렇게하면 리팩토링을 통해 모든 사람이 같은 페이지에있을 수 있다는 장점이 있지만, 실수를 피하고 필요한 경우 유지 보수 할 수있는 방법 그룹화에 대한 정보를 다른 사람으로부터 얻을 수 있습니다.

이런 식으로하면 코드 검토 기능이 내장되어 있다고 생각할 수 있습니다. 이를 통해 코드를 체크인하고 검토 할 준비가되는 즉시 적절한 양의 개발자가 코드에서 사인 오프 할 수 있습니다. 여전히 누락 된 부분이 있는지 코드에서 확인하도록 할 수도 있지만 검토 프로세스가 더 짧은 지 확인하는 데 많은 도움이됩니다.

작업이 쉽게 이루어 지도록 배포되지 않으므로 모든 상황, 팀 또는 회사에서 작동하지 않을 수 있습니다. 또한 Dev Time의 오용으로도 잘못 해석 될 수 있습니다. 이 그룹 코드는 리 팩터 자체뿐만 아니라 관리자로부터의 구매가 필요합니다.

이 아이디어를 관리자에게 판매 할 수 있도록 코드 검토 비트와 처음부터 물건의 위치를 ​​아는 모든 사람을 언급하십시오. 개발자가 많은 새 파일을 검색하는 데 시간을 낭비하지 않도록 방지하는 것이 좋습니다. 또한, 일이 끝나거나 "완전히 누락 된"장소에 대해 개발자가 PO를받지 못하게하는 것이 일반적으로 좋습니다. (용융이 적을수록 IMO가 더 좋습니다.)

이 방법으로 하나의 파일을 리팩토링하면 성공적이고 유용한 리팩터링에 대한 승인을보다 쉽게 ​​얻을 수 있습니다.

그러나 당신은 당신의 리 팩터, 행운을 빌어하기로 결정했습니다!


이것은 팀 조정을 달성하기 위해 매우 중요한 팀 조정을 달성하는 정말 좋은 방법을 포착 한 환상적인 제안입니다. 또한, 일부 브랜치가 master처음으로 다시 병합 될 수없는 경우 최소한 그 브랜치로의 병합을 처리하는 데 도움을 줄 수있는 최소한의 공간에 모두가 있습니다.
콜린 영

코드 몹 제안을위한 +1
Jon Raynor

1
이것은 문제의 사회적 측면을 정확하게 다룬다.
ChuckCottrill

4

이 문제를 해결하려면 공유 리소스 (코드 자체)를 변경하려고하므로 다른 팀의 바이 인이 필요합니다. 즉, 사람들을 방해하지 않고 거대한 모 놀리 식 파일을 가지고 "이주"할 수있는 방법이 있다고 생각합니다.

또한 개별 파일의 크기 외에 많은 파일이 제어 할 수없이 커지지 않는 한 모든 파일을 한 번에 타겟팅하지 않는 것이 좋습니다 .

이와 같은 큰 파일을 리팩터링하면 예기치 않은 문제가 자주 발생합니다. 첫 번째 단계는 큰 파일 이 현재 마스터 또는 개발 지점에있는 것 이상의 추가 기능을 누적하지 못하게하는 입니다.

이 작업을 수행하는 가장 좋은 방법은 기본적으로 큰 파일에 대한 특정 추가 사항을 차단하는 커밋 후크를 사용하는 것이지만 커밋 메시지의 마법 같은 주석으로 대체 할 수 있습니다 @bigfileok. 고통스럽지 않지만 추적 할 수있는 방식으로 정책을 무효화 할 수 있어야합니다. 이상적으로 커밋 후크를 로컬에서 실행할 수 있어야 하며 오류 메시지 자체에서이 특정 오류를 무시하는 방법을 알려야합니다 . 또한 이것은 내 취향에 불과하지만 커밋 메시지에서 실제로 발생하지 않은 오류를 억제하는 인식 할 수없는 마법의 주석 또는 마법의 주석은 커밋 시간 경고 또는 오류이어야하므로 실수로 관계없이 후크를 억제하도록 사람들을 교육하지 마십시오. 그들이 필요한지 아닌지.

커밋 후크는 새 클래스를 확인하거나 다른 정적 분석 (임시 여부)을 수행 할 수 있습니다. 현재 파일보다 10 % 더 큰 줄 또는 문자 수를 선택하고 큰 파일이 새로운 제한을 초과하여 증가 할 수 없다고 말할 수도 있습니다. 또한 큰 파일을 너무 많은 행이나 너무 많은 문자 또는 w / e로 증가시키는 개별 커밋을 거부 할 수 있습니다.

큰 파일이 새 기능 축적을 중지하면 한 번에 하나씩 파일을 리팩터링 할 수 있습니다 (그리고 커밋 후크에 의해 적용되는 임계 값을 줄여 다시 커지지 않도록 할 수 있습니다).

결국 큰 파일은 커밋 후크를 완전히 제거 할 수있을 정도로 작습니다.


-3

집까지 기다립니다. 파일을 분할하고 커밋하고 마스터에 병합하십시오.

다른 사람들은 다른 변경 사항과 마찬가지로 아침에 변경 사항을 기능 지점으로 가져와야합니다.


3
그래도 그래도 리팩토링을 변경 사항과 병합해야 할 것입니다.
Hoff


1
글쎄, 그들은 모두 파일을 변경하면 실제로 병합을 처리해야합니다.
Laiv

9
이것은 "서프라이즈, 나는 당신의 모든 것을 깨뜨 렸습니다"라는 문제가 있습니다. OP는이 작업을 수행하기 전에 바이 인 및 승인을 받아야하며 예정된 시간에 다른 사람이 "진행 중"파일을 가지고 있지 않은 경우이를 수행해야합니다.
computercarguy

6
cthulhu의 사랑을 위해 이것을하지 마십시오. 팀에서 일할 수있는 최악의 방법입니다.
Monica
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.