여러 하위 프로젝트에서 프로젝트를 분리하는 경우


30

작업중 인 프로젝트를 하나의 저장소가 아닌 두 개의 저장소로 나누는 것이 타당한 지 알고 싶습니다.

내가 말할 수있는 것에서 :

  • 프론트 엔드는 html + js로 작성됩니다
  • .net의 백엔드
  • 백엔드는 프론트 엔드에 의존하지 않으며 프론트 엔드는 백엔드에 의존하지 않습니다
  • 프론트 엔드는 백엔드에서 구현 된 편안한 API를 사용합니다.
  • 프런트 엔드는 모든 정적 http 서버에서 호스팅 될 수 있습니다.

현재 저장소는 다음과 같은 구조를 가지고 있습니다.

뿌리:

  • 프론트 엔드 / *
  • 백엔드 / *

두 프로젝트를 동일한 저장소에 유지하는 것은 실수라고 생각합니다. 두 프로젝트 모두 서로간에 종속성이 없으므로 개별 리포지토리와 하위 모듈이있는 상위 리포지토리에 속해야합니다.

나는 그것이 무의미하고 우리가 그렇게하면 아무런 이익을 얻지 못할 것이라고 들었습니다.

내 주장 중 일부는 다음과 같습니다.

  • 서로 의존하지 않는 두 개의 모듈이 있습니다.
  • 두 프로젝트의 소스 히스토리를 장기적으로 보유하면 상황이 복잡해질 수 있습니다 (커밋의 절반은 찾고있는 버그와 전혀 관련이없는 프론트 엔드에서 무언가를 찾기 위해 히스토리를 검색하십시오)
  • 충돌 및 병합
  • 한 개발자는 백엔드에서만 작업 할 수 있지만 항상 프론트 엔드 또는 다른 방법으로 가져와야합니다.
  • 장기적으로는 배포 할시기입니다. 어떤 식 으로든 프런트 엔드는 하나의 백엔드 서버를 사용하면서 여러 정적 서버에 배포 할 수 있습니다. 모든 경우에 사람들은 전체 백엔드를 복제하거나 모든 서버에 프론트 엔드 만 푸시하거나 백엔드를 제거하도록 사용자 정의 스크립트를 작성해야합니다. 하나만 필요한 경우 프런트 엔드 또는 백엔드 만 푸시 / 풀하기 만하면됩니다.
  • 반대 주장 (한 사람이 두 프로젝트 모두에서 일할 수 있음), 하위 모듈로 세 번째 저장소를 만들고 함께 개발하십시오. 히스토리는 개별 모듈에서 분리되어 유지되며 백엔드 / 프론트 버전이 실제로 동기화되어 작동하는 태그를 항상 작성할 수 있습니다. 하나의 리포지토리에서 프런트 엔드 / 백엔드를 함께 사용한다고해서 함께 작동한다는 의미는 아닙니다. 두 역사를 하나의 큰 레포로 병합하고 있습니다.
  • 프런트 엔드 / 백엔드를 하위 모듈로 사용하면 프로젝트에 프리랜서를 추가하려는 경우 작업이 쉬워집니다. 어떤 경우에는 실제로 코드베이스에 대한 전체 액세스 권한을 부여하고 싶지 않습니다. 하나의 큰 모듈이 있으면 "외부인"이보고 편집 할 수있는 것을 제한하려는 경우 작업이 더 어려워집니다.
  • 버그 소개 및 버그 수정, 프론트 엔드에 새로운 버그를 삽입했습니다. 그런 다음 누군가 백엔드에서 버그를 수정합니다. 하나의 리포지토리를 사용하면 새 버그 이전에 롤백하면 백엔드가 롤백되므로 수정하기가 어려울 수 있습니다. 프론트 엔드의 버그를 수정하는 동안 백엔드가 작동하도록하려면 다른 폴더에 백엔드를 복제해야합니다 ... 그런 다음 물건을 다시 만들려고합니다 ... 두 저장소를 갖는 것은 하나의 리포지토리의 HEAD를 이동했기 때문에 고통스럽지 않습니다. 다른 것을 바꾸지 마십시오. 그리고 다른 버전의 백엔드에 대한 테스트는 어려움이 없습니다.

누군가 나를 설득하기 위해 더 많은 주장을 주거나 적어도 두 개의 하위 모듈로 프로젝트를 나누는 것이 무의미한 (더 복잡한) 이유를 말해 줄 수 있습니까? 이 프로젝트는 새롭고 코드베이스는 며칠이어서 너무 빨리 고쳐지지 않습니다.

답변:


23

우리 회사에서는 시스템의 모든 구성 요소에 대해 별도의 SVN 저장소를 사용합니다. 나는 그것이 매우 좌절된다고 말할 수 있습니다. 우리의 빌드 프로세스는 너무 많은 추상화 계층을 가지고 있습니다.

Java 로이 작업을 수행하므로 javac 컴파일, JibX 바인딩 컴파일, XML 유효성 검사 등으로 무거운 빌드 프로세스가 있습니다.

사이트의 경우 실제로 "빌드"하지 않으면 (예 : 바닐라 PHP) 큰 문제가되지 않을 수 있습니다.

제품을 여러 리포지토리로 분할 할 때의 단점

  1. 빌드 관리-코드를 체크 아웃하고 자체 포함 빌드 스크립트를 실행하며 실행 가능 / 설치 가능 / 배포 가능 제품을 가질 수 없습니다. 여러 저장소로 이동하고 여러 내부 빌드 스크립트를 실행 한 다음 아티팩트를 조립하는 외부 빌드 시스템이 필요합니다.
  2. 변경 내용 추적-누가, 언제, 왜 변경했는지 확인합니다. 프론트 엔드의 버그 수정에 백엔드 변경이 필요한 경우 나중에 다시 참조 할 수있는 두 가지 경로가 있습니다.
  3. 관리-관리해야하는 사용자 계정 수, 암호 정책 등을 두 배로 늘리시겠습니까?
  4. 병합-새로운 기능으로 인해 많은 코드가 변경 될 수 있습니다. 프로젝트를 여러 리포지토리로 분할하면 필요한 병합 수를 곱하게됩니다.
  5. 분기 생성-분기와 동일하게 분기를 만들려면 이제 각 리포지토리에 분기를 만들어야합니다.
  6. 태그 지정-코드를 성공적으로 테스트 한 후 릴리스 할 버전에 태그를 지정하려고합니다. 이제 각 저장소마다 하나씩 여러 개의 태그를 작성할 수 있습니다.
  7. 찾기 어려운-아마도 프론트 엔드 / 백엔드가 간단하지만 미끄러운 경사가됩니다. 충분한 모듈로 분할하면 개발자는 일부 코드 조각이 소스 제어에서 어디에 있는지 조사해야 할 수 있습니다.

우리의 제품은 14 개의 다른 저장소로 나뉘어져 있고 각 저장소는 4-8 모듈로 나뉘어 있기 때문에 제 경우는 약간 극단적입니다. 내가 기억한다면, 우리는 약 80 개 정도의 "패키지"를 가지고 있으며 그것들은 모두 개별적으로 체크 아웃하고 조립해야합니다.

백엔드 / 프론트 엔드가있는 경우는 덜 복잡 할 수 있지만 여전히 반대합니다.

극단적 인 예는 거의 모든 것에 대한 강력한 논쟁이 될 수 있습니다 :)

내가 결정하는 데 사용할 기준

다음 요소를 고려한 후 제품을 여러 소스 코드 리포지토리로 분할하는 것이 좋습니다.

  1. 빌드-각 구성 요소를 빌드 한 결과가 함께 병합되어 제품을 형성합니까? 여러 구성 요소의 .class 파일을 일련의 .jar 또는 .war 파일로 결합하는 것과 같습니다.
  2. 배포-하나의 장치 또는 다른 서버로 이동하는 다른 장치로 함께 배포되는 구성 요소가 있습니까? 예를 들어, 데이터베이스 스크립트는 DB 서버로 이동하고 javascript는 웹 서버로 이동합니다.
  3. 공동 변경-자주 또는 함께 변경되는 경향이 있습니까? 귀하의 경우에는 개별적으로 변경 될 수 있지만 여전히 자주 변경 될 수 있습니다.
  4. 분기 / 병합 빈도-모든 사람이 트렁크를 체크인하고 분기가 드물다면이를 제거 할 수 있습니다. 자주 분기하고 병합하면 악몽이 될 수 있습니다.
  5. 민첩성-SaaS와 같은 순간에 변경 사항을 개발, 테스트, 릴리스 및 배포해야하는 경우 지점과 저장소를 저글링하는 데 소중한 시간을 소비하지 않고 변경할 수 있습니까?

당신의 주장

또한이 분할에 대한 대부분의 주장에 동의하지 않습니다. 이 긴 답변이 더 길어질 것이기 때문에 모두 논쟁하지는 않지만 눈에 띄는 몇 가지가 있습니다.

서로 의존하지 않는 두 개의 모듈이 있습니다.

무의미한 말. 백엔드를 가져 가면 프론트 엔드가 작동합니까? 그것이 내가 생각했던 거죠.

두 프로젝트의 소스 히스토리를 장기적으로 보유하면 상황이 복잡해질 수 있습니다 (커밋의 절반은 찾고있는 버그와 전혀 관련이없는 프론트 엔드에서 무언가를 찾기 위해 히스토리를 검색하십시오)

프로젝트 루트가 프론트 엔드 /와 백엔드 /로 분리 된 경우 해당 계층의 히스토리를 독립적으로 볼 수 있습니다.

충돌 및 병합 약.

프로젝트를 다른 저장소로 분할해도 문제가 해결되지 않습니다. 프론트 엔드 충돌 및 백엔드 충돌은 저장소 1 회 충돌 횟수 2 개 또는 리포지토리 곱하기 충돌 횟수 1 회에 관계없이 여전히 2 개의 충돌로 남아 있습니다. 누군가는 여전히 그것들을 해결해야합니다.

2 repos가 프론트 엔드 개발자가 프론트 엔드 코드를 병합 할 수 있고 백엔드 개발자가 백엔드 코드를 병합 할 수 있다는 것을 염려 할 경우 SVN을 사용하여 단일 저장소로이를 수행 할 수 있습니다. SVN은 모든 수준에서 병합 할 수 있습니다. 어쩌면 그것은 git 또는 mercurial 제한입니다 (두 태그를 모두 사용 했으므로 어떤 SCM을 사용하는지 확실하지 않습니다)?

반면에

이 모든 것을 말하면서 프로젝트를 여러 모듈이나 저장소로 나누는 경우가 있습니다. Solr을 제품에 통합 한 특정 프로젝트에 대해 한 번 옹호하기까지했습니다. Solr은 물론 별도의 서버에서 실행되며 변경 세트가 검색과 관련이 있고 (제품이 검색보다 훨씬 많은 경우) 변경 프로세스가 있고 코드 아티팩트 나 빌드 아티팩트가 공유되지 않은 경우에만 변경됩니다.


어머니 께서 말씀하신 것처럼 모든 것에 대한 조절 ...
William Payne

글을 쓰는 시점에서 나는 백엔드없이 프론트 엔드를 쓰고 있습니다. json 파일로 백엔드를 에뮬레이트하고 브라우저에서 indexedDB로 완전히 에뮬레이션 할 수도 있습니다. 예, 백엔드는 json을 제공하는 서버 일뿐입니다. 수신 된 데이터가 API를 준수하는 한 다른 것으로 대체 될 수 있습니다. 두 프로젝트 모두 다른 빌드 시스템을 사용합니다. 요컨대, 웹 사이트와 모바일 안드로이드 앱을 갖는 것과 거의 같습니다. 웹 서버 저장소 내에 모바일 애플리케이션 추가
Loïc Faure-Lacroix

또한 명확하지 않은 경우 백엔드 및 프런트 엔드가 사용자 / 관리자 인터페이스가 아닙니다. 그러나 프론트 엔드는 단지 아약스 인터페이스이며 백엔드는 json을 제공합니다. 사용자와 역할은 다르게 처리되며 관리 인터페이스는 프론트 엔드에 있습니다. 아이디어는 두 부분을 모두 격리하고 자바 스크립트로 생성 된 html이 서버에서 생성 된 html을로드하지 못하게하는 것입니다. 서버는 json 또는 xml 만 제공해야합니다.
Loïc Faure-Lacroix

1
그런 다음 빌드 또는 배포 문제가 없으므로 괜찮을 수 있습니다. 그러나 다시 크게 변경하면 API를 변경해야 할 수 있습니다. 프런트 엔드와 백엔드 모두에 영향을 미치므로 두 번 분기하고 두 번 병합하고 두 번 태그하는 등의 작업을 수행합니다. 3 ... 4 ... 12 ... 20으로 바뀌지 마십시오. 나쁜 생각은 아닙니다.
Brandon

적절한 버전 관리를 통해 API가 변경 되더라도 API 버전을 지원하는 각 프런트 엔드마다 분기 버전을 만들 수 있습니다. 백엔드는 약간의 "역방향"호환성을 가져야하며 가능한 오래 오래된 API를 계속 작동시켜야합니다.
Loïc Faure-Lacroix

3

귀하의 주장 중 일부는 유효하고 일부는 유효하지 않습니다.

서로 의존하지 않는 두 개의 모듈이 있습니다.

실제로는 사실이 아닙니다. 통신하려면 프런트 엔드와 백 엔드에 공통 인터페이스 (설명)가 있어야합니다. 따라서 공통 리포지토리에 둘 다 선호한다는 약한 주장이됩니다. 그러나 그다지 큰 차이는 없지만 약한 주장입니다.

두 프로젝트의 소스 히스토리를 장기적으로 보유하면 상황이 복잡해질 수 있습니다 (커밋의 절반은 찾고있는 버그와 전혀 관련이없는 프론트 엔드에서 무언가를 찾기 위해 히스토리를 검색하십시오)

이것은 가짜 주장입니다. 특정 버그가 어떻게 고쳐 졌는지 알아 보려면, commit에 수정 사항이 포함 된 버그 추적기를 살펴보십시오. 그리고 특정 코드 조각이 어떻게 발전했는지 알고 싶다면 단일 파일의 역사를 살펴보십시오. 두 경우 모두 저장소에 다른 모듈의 다른 파일이 있으면 어떤 식 으로든 복잡하지 않아야합니다.

충돌 및 병합

이것은 가짜 주장입니다. 변경 사항을 커밋 / 푸시하기 전에 전체 리포지토리를 동기화해야하는 (반 정도의) VCS는 알 수 없습니다. 기껏해야 변경된 파일이 들어있는 폴더 (및 파일 자체 만)를 동기화해야합니다.

한 개발자는 백엔드에서만 작업 할 수 있지만 항상 백엔드 또는 다른 방법으로 가져와야합니다.

이것은 이전과 같은 가짜 주장입니다.

장기적으로는 배포 할시기입니다. 어떤 식 으로든 프런트 엔드는 하나의 백엔드 서버를 사용하면서 여러 정적 서버에 배포 할 수 있습니다. 모든 경우에 사람들은 전체 백엔드를 복제하거나 모든 서버에 프론트 엔드 만 푸시하거나 백엔드를 제거하도록 사용자 정의 스크립트를 작성해야합니다. 하나만 필요한 경우 프런트 엔드 또는 백엔드 만 푸시 / 풀하기 만하면됩니다.

사람들이 배포를 계획하는 방식에 따라 유효한 인수가 될 수 있습니다. 서버에서 zip 파일 / tarbal의 압축을 풀어 배포를 수행하는 경우 리포지토리 구성 방식은 중요하지 않습니다. 서버에서 리포지토리를 체크 아웃하여 배포를 수행하는 경우 별도로 배포 된 모듈에 대해 별도의 리포지토리를 사용하는 것이 좋습니다.

반대 주장 (한 사람이 두 프로젝트 모두에서 일할 수 있음), 하위 모듈로 세 번째 저장소를 만들고 함께 개발하십시오. 히스토리는 개별 모듈에서 분리되어 유지되며 백엔드 / 프론트 버전이 실제로 동기화되어 작동하는 태그를 항상 작성할 수 있습니다. 하나의 리포지토리에서 프런트 엔드 / 백엔드를 함께 사용한다고해서 함께 작동한다는 의미는 아닙니다. 두 역사를 하나의 큰 레포로 병합하고 있습니다.

이것은 유효한 주장이지만 그렇게 강력하지는 않습니다.

프런트 엔드 / 백엔드를 하위 모듈로 사용하면 프로젝트에 프리랜서를 추가하려는 경우 작업이 쉬워집니다. 어떤 경우에는 실제로 코드베이스에 대한 전체 액세스 권한을 부여하고 싶지 않습니다. 하나의 큰 모듈이 있으면 "외부인"이보고 편집 할 수있는 것을 제한하려는 경우 작업이 더 어려워집니다.

유효한 인수입니다.

버그 소개 및 버그 수정, 프론트 엔드에 새로운 버그를 삽입했습니다. 그런 다음 누군가 백엔드에서 버그를 수정합니다. 하나의 리포지토리를 사용하면 새 버그 이전에 롤백하면 백엔드가 롤백되므로 수정하기가 어려울 수 있습니다.

그것은 하나의 모듈에 두 개의 버그 수정이 끝나면 첫 번째 모듈을 되돌릴 수 없다는 것을 의미하기 때문에 가짜 주장입니다. 절반 정도의 VCS를 사용하면 이전 커밋에 대해 거의 롤백 할 수 있습니다 (종종 HEAD의 맨 위에서조차도 변경 사항을 되 돌리는 새로운 커밋을 만드는 경우가 종종 있음).

프론트 엔드의 버그를 수정하는 동안 백엔드가 작동하도록하려면 다른 폴더에 백엔드를 복제해야합니다 ... 그런 다음 물건을 다시 만들려고합니다 ... 두 저장소를 갖는 것은 하나의 리포지토리의 HEAD를 이동했기 때문에 고통스럽지 않습니다. 다른 것을 바꾸지 마십시오. 그리고 다른 버전의 백엔드에 대한 테스트는 어려움이 없습니다.

이것은 실제로 꽤 좋은 주장입니다. 두 개의 리포지토리를 사용하면 배포 된 프런트 엔드 및 백 엔드가 동기화되지 않은 시나리오를 쉽게 테스트 할 수 있습니다.


솔직히 말해서, 대부분의 가짜 주장은 가지로 해결할 수 있습니다. 프런트 엔드 용 분기 및 백엔드 용 분기 동기화 마스터. 그러나 어떤 식 으로든 그런 지점을 처리하면 두 개의 저장소를 갖는 것보다 일이 더 복잡해집니다.
Loïc Faure-Lacroix

1
@Sybiam : 실제로는 모든 변경 사항이 트렁크 / 메인에만 적용 되더라도 단일 리포지토리를 사용할 때 발생할 수있는 문제를 강조하지 않기 때문에 실제로는 논쟁의 여지가 있습니다.
Bart van Ingen Schenau

나는 당신의 비판이 유효하다고 생각합니다. 나는 그것이 그 질문의 요점이라고 생각하지 않습니다.
sylvanaar

2

이 게시물은 약간 낡았지만 기여하고 싶습니다. 백엔드는 실제로 프론트 엔드에 대해 알지 못하지만 프론트 엔드에는 백엔드의 API와 일치하는 요청이 있어야합니다. 백엔드를 REST API로 간주하는 경우 swagger YAML 인터페이스와 같은 인터페이스 파일을 정의 할 수 있습니다. 이제 실제로 3 개의 프로젝트가 있으며, 적절하다고 생각되는대로 개별 리포지토리로 나눌 수 있습니다.

  • API 정의
  • 백엔드
  • 프론트 엔드

API 정의는 다른 두 프로젝트의 종속성이므로 maven을 종속성 주입 도구로 사용한다고 가정 해 보겠습니다. 그런 다음 버전 관리를 수행하려는 정도에 따라 다릅니다. 프로젝트가 항상 호환 가능한 상태에 있지만 더 많은 오버 헤드가 필요하도록 변경을 수행 할 때마다 API 정의 프로젝트의 버전을 충돌시킬 수 있습니다. 오버 헤드가 적은 인터페이스에 만족하지만 종종 비 호환성이있을 수 있습니다. 그러나 프론트 엔드 및 백엔드에서 API 정의를 시행하는 한 프로젝트를 다른 리포지토리로 분할하는 것이 좋습니다.

이러한 문제는 종속성 관리에 관한 것입니다. 프로젝트가 분할되지 않고 동일한 저장소에 있더라도 웹 사이트가 프론트 엔드와 백 엔드가 동기화되지 않은 상태에 놓이기는 매우 쉽습니다. 실제로 이것을 막을 수있는 유일한 방법은 실제로 두 계약 간의 계약을 정의하는 것입니다.하지만 대신 인터페이스에 코딩하는 것처럼 프론트 엔드와 백엔드의 구현을 결합하지 않는 방식으로 계약을 수행하려고합니다 OO 프로그래밍에서의 구현.

또한이 인터페이스 파일을 유지 관리하는 오버 헤드가 발생한다는 비판을 선제 적으로 처리하기 위해 swagger는 JAX-RS와 같은 다른 프로그래밍 언어 및 프레임 워크에 대한 코드 스텁을 생성 할 수도 있습니다. 따라서 선택한 기술로 인터페이스를 생성 한 다음이 인터페이스를 구현할 수 있습니다. 또한 백엔드에 매우 유용한 문서를 추가하여 프론트 엔드 개발자가 작업을보다 쉽게 ​​수행 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.