고도로 맞춤화 된 소프트웨어는 어떻게 구성합니까?


28

전 세계의 다양한 고객을 위해 고도로 맞춤화 된 대형 소프트웨어 프로젝트를 진행하고 있습니다. 이것은 우리가 다양한 고객들 사이에서 공통적 인 80 % 코드를 가질 수 있음을 의미하지만, 한 고객에서 다른 고객으로 변경해야하는 많은 코드도 있습니다. 과거에는 개별 리포지토리 (SVN)에서 개발을 수행했으며 새로운 프로젝트가 시작될 때 (대규모 고객은 많지만 대규모 프로젝트) 우리의 요구에 가장 적합한 코드 기반의 과거 프로젝트를 기반으로 다른 리포지토리를 만들었습니다. 이것은 과거에 효과가 있었지만 몇 가지 문제가 발생했습니다.

  • 한 리포지토리에서 수정 된 버그 는 다른 리포지토리에서 패치되지 않습니다. 이것은 조직의 문제 일 수 있지만 5 개의 다른 리포지토리에서 버그를 수정하고 패치하기가 어렵습니다.이 리포지토리를 유지 관리하는 팀은 다른 지역에있을 수 있으며 테스트 환경이 없다는 것을 명심하십시오. 일정이나 요구 사항을 모릅니다 (한 국가의 "버그"는 다른 국가의 "기능"일 수 있음).
  • 한 프로젝트를 위해 만들어 졌거나 다른 프로젝트에 유용 할 수있는 기능 및 개선 사항은 다른 프로젝트에서 유용하거나 다른 프로젝트에서 사용되는 경우 종종 한 코드베이스에서 다른 코드베이스로 병합하는 데 큰 두통을 유발합니다 (두 지점이 1 년 동안 독립적으로 개발 되었기 때문에) ).
  • 하나의 개발 브랜치에서 수행 된 리팩토링 및 코드 개선 은 브랜치간에 이러한 모든 변경 사항을 병합해야하는 경우 손실되거나 이익보다 더 큰 피해를 야기합니다.

우리는 이제 이러한 문제를 해결하는 방법을 논의하고 있으며 지금까지이 문제를 해결하는 방법에 대한 다음 아이디어를 생각해 냈습니다.

  1. 일반적인 버그 수정이 통합 된 중앙 리포지토리를 보유하고 모든 프로젝트가이 중앙 리포지토리의 변경 사항을 정기적으로 (예 : 매일) 병합함으로써 개발을 개별 지점으로 유지 하지만 더 효과적으로 구성 할 수 있습니다. 이를 위해서는 엄청난 훈련과 지점 간 합병에 많은 노력이 필요합니다. 그래서 나는 그것이 효과가있을 것이라고 확신하지 못하며, 특히 시간 압력이 가해질 때이 훈련을 유지할 수 있습니다.

  2. 별도의 개발 지점을 포기하고 플러그 가능한 모듈 및 구성 옵션을 통해 모든 코드가있는 중앙 코드 저장소를 사용하고 사용자 지정을 수행하십시오. 우리는 이미 코드의 종속성을 해결하기 위해 Dependency Injection 컨테이너를 사용하고 있으며 대부분의 코드에서 MVVM 패턴을 따라 비즈니스 로직과 UI를 명확하게 분리하고 있습니다.

두 번째 방법은 더 우아해 보이지만이 방법에는 해결되지 않은 많은 문제가 있습니다. 예 : 모델 / 데이터베이스에서 변경 / 추가를 처리하는 방법 Entity Framework와 함께 .NET을 사용하여 강력한 형식의 엔터티를 갖습니다. 데이터 모델을 어지럽히 지 않고 한 고객에게는 필요하지만 다른 고객에게는 쓸모없는 속성을 처리하는 방법을 알 수 없습니다. 우리는 위성 테이블을 사용하여 데이터베이스 에서이 문제를 해결하려고 생각합니다 (특정 엔티티에 대한 추가 열이 원래 엔티티에 1 : 1 매핑되어있는 별도의 테이블이 있음). 이것은 데이터베이스 일뿐입니다. 이것을 코드에서 어떻게 처리합니까? 우리의 데이터 모델은이 방법을 사용하여 각 고객에 대해 확장 할 수없는 중앙 라이브러리에 있습니다.

나는 우리가이 문제로 어려움을 겪고있는 유일한 팀이 아니라고 확신하며 주제에 대한 자료가 거의 없다는 사실에 놀랐습니다.

그래서 내 질문은 다음과 같습니다.

  1. 고도로 맞춤화 된 소프트웨어에 대한 경험은 무엇이며, 어떤 접근 방식을 선택했으며 어떻게 작동합니까?
  2. 어떤 접근법을 추천하고 왜 그럴까요? 더 나은 접근 방법이 있습니까?
  3. 추천 할만한 주제에 관한 좋은 책이나 기사가 있습니까?
  4. 기술 환경 (.NET, Entity Framework, WPF, DI)에 대한 특정 권장 사항이 있습니까?

편집하다:

모든 제안에 감사드립니다. 대부분의 아이디어는 우리 팀에서 이미 가지고있는 아이디어와 일치하지만 아이디어를 경험 한 경험과 더 나은 구현을위한 팁을 보는 것이 실제로 도움이됩니다.

나는 우리가 어떤 길로 갈지 확신하지 못하고 결정을 내릴 수 없지만 (단독), 나는 이것을 팀에서 전달할 것이며 도움이 될 것이라고 확신합니다.

현재 테너는 다양한 고객 별 모듈을 사용하는 단일 저장소 인 것 같습니다. 아키텍처가 이것에 달려 있는지 또는 확실하게 만들기 위해 얼마나 투자해야하는지 확신하지 못하므로 일부는 별도의 저장소에 잠시 살 수 있지만 그것이 유일한 장기 해결책이라고 생각합니다.

모든 답변에 다시 한번 감사드립니다!


데이터베이스 테이블을 코드로 취급하십시오.

우리는 서브 버전 리포지토리에 데이터베이스 스크립트가 있다는 의미에서 이미이 작업을 수행하고 있지만 위에서 언급 한 문제를 실제로 해결하지는 않습니다. 우리는 데이터베이스 모델에 키-값 스타일 테이블을 갖고 싶지 않다. 많은 문제가 있기 때문이다. 그렇다면 어떻게 모든 고객에 대해 공유 코드 저장소를 유지하면서 개별 고객의 모델에 추가를 허용 할 수 있습니까?
aKzenT

답변:


10

근본적인 문제는 코드 리포지토리 유지 관리뿐만 아니라 적절한 아키텍처부족한 것 같습니다 .

  1. 모든 시스템이 항상 공유 할 시스템의 핵심 / 본질은 무엇입니까?
  2. 각 고객에게 어떤 개선 / 편차가 필요합니까?

프레임 워크 또는 표준 라이브러리는 전자를 포괄하며, 후자는 애드온 (플러그인, 서브 클래스, DI, 코드 구조에 적합한 모든 것)으로 구현됩니다.

지점과 분산 개발을 관리하는 소스 제어 시스템도 도움이 될 것입니다. 나는 Mercurial의 팬이고, 다른 사람들은 Git을 선호합니다. 프레임 워크는 기본 브랜치가되고 각 사용자 지정 시스템은 하위 브랜치가됩니다.

시스템을 구현하는 데 사용되는 특정 기술 (.NET, WPF 등)은 크게 중요하지 않습니다.

이 권리를 얻는 것이 쉽지 는 않지만 장기적인 생존에 중요 합니다. 물론 기다릴수록 기술 부채가 더 커집니다.

Software Architecture : Organizational Principles and Patterns 책이 유용 할 수 있습니다.

행운을 빕니다!


3
예. 건축은 종종 기술적 인 것보다 심리적 인 것입니다. 제품에 전적으로 초점을 맞추면 구성 요소가 해당 제품에만 유용한 작업 고장이 발생합니다. 반면에보다 일반적으로 유용한 라이브러리 세트를 작성하는 데 중점을두면 더 넓은 상황에 배치 할 수있는 기능 세트를 빌드합니다. 물론 핵심은 특정 상황에 따라이 두 극단 사이의 올바른 균형을 찾는 것입니다.
William Payne

많은 지점 (> 90 %) 사이에 큰 부분이 있다고 생각하지만 마지막 10 %는 항상 다른 위치에 있으므로 일부 유틸리티 라이브러리를 제외하고 고객 특정 변경 사항을 상상할 수없는 구성 요소가 거의 없습니다. 비즈니스 로직을 포함하지 않습니다.
akzenT

@ aKzenT : 흠 ... 상상하지 말고 대신 측정하십시오. 코드를 조사하고 사용자 정의가 발생한 모든 위치를보고, 수정 된 구성 요소 목록을 작성하고, 각 구성 요소가 얼마나 자주 수정되었는지 확인하고, 실제로 수행 된 수정의 종류와 패턴에 대해 생각하십시오. 그것들은 장식 적인가 알고리즘 적인가? 기본 기능을 추가 또는 변경하고 있습니까? 각 유형의 변경에 대한 이유는 무엇입니까? 다시 말하지만 이것은 어려운 일 이며, 발견 한 내용의 의미를 좋아하지 않을 수 있습니다.
Steven A. Lowe

1
아키텍처에 대해 더 많이 생각하기 전에이 결정을 내릴 수없고, 공통적이거나 공통적이어야하는 부분을 식별 한 다음 단일 저장소로 살 수 있는지 또는 포크가 필요한지 확인하기 때문에이 답변을 받아 들였습니다. 적어도 순간). 이 답변은이 최고의 IMO를 반영합니다. 그래도 다른 모든 게시물에 감사드립니다!
akzenT

11

내가 일한 한 회사도 같은 문제를 겪고 있었으며 문제를 해결하는 방법은 다음과 같습니다. 모든 새 프로젝트를위한 공통 프레임 워크가 만들어졌습니다. 여기에는 모든 프로젝트에서 동일해야하는 모든 것이 포함됩니다. 예를 들어 양식 생성 도구, Excel로 내보내기, 로깅. 이 공통 프레임 워크는 (새로운 프로젝트가 새로운 기능을 필요로 할 때) 개선 될뿐만 아니라 결코 포크되지 않도록하기 위해 노력했습니다.

이 프레임 워크를 기반으로 고객 별 코드는 별도의 리포지토리에서 유지 관리되었습니다. 유용하거나 필요한 경우 프로젝트간에 버그 수정 및 개선 사항을 복사하여 붙여 넣습니다 (문제에 설명 된 모든 경고 사항 포함). 그러나 전 세계적으로 유용한 개선 사항이 공통 프레임 워크로 들어갑니다.

모든 고객을 위해 공통 코드베이스로 모든 것을 갖는 것은 몇 가지 장점이 있지만, 반면에, if각 고객에 대해 프로그램이 다르게 동작하도록하는 수많은 경우가있을 때 코드를 읽는 것이 어려워집니다 .

편집 : 이것을 이해하기 쉬운 일화 일화 :

해당 회사의 영역은 창고 관리이며, 창고 관리 시스템의 한 가지 작업은 들어오는 상품을위한 무료 저장 위치를 ​​찾는 것입니다. 쉬운 것처럼 들리지만 실제로는 많은 제약과 전략이 지켜 져야합니다.

한 시점에서 경영진은 프로그래머에게 유연하고 매개 변수를 지정할 수있는 모듈을 만들어 저장 위치를 ​​찾을 수 있도록 요청했습니다.이 모듈은 여러 가지 다른 전략을 구현했으며 모든 후속 프로젝트에서 사용해야했습니다. 고귀한 노력으로 복잡한 모듈이 생겨 이해하고 유지하기가 매우 어려웠습니다. 다음 프로젝트에서는 프로젝트 리더가 해당 창고에서 어떻게 작동하는지 파악할 수 없었고 해당 모듈의 개발자가 사라 졌으므로 결국 무시하고 해당 작업에 대한 사용자 정의 알고리즘을 작성했습니다.

몇 년 후,이 모듈이 원래 사용 된 창고의 레이아웃이 변경되었으며 모든 유연성을 갖춘 모듈이 새로운 요구 사항과 일치하지 않았습니다. 그래서 거기에서도 커스텀 알고리즘으로 대체했습니다.

LOC는 좋은 측정 방법은 아니지만 어쨌든 "유연한"모듈의 크기는 ~ 3000 LOC (PL / SQL)이고 동일한 작업에 대한 사용자 지정 모듈은 ~ 100..250 LOC가 걸립니다. 따라서 유연성을 얻으려고 노력하면 원하는 재사용 성을 얻지 않고 코드베이스의 크기를 크게 늘 렸습니다.


의견을 보내 주셔서 감사합니다. 이것은 설명 된 첫 번째 솔루션의 확장이며 우리는 이것에 대해서도 생각했습니다. 그러나 대부분의 라이브러리는 일부 핵심 엔터티를 사용하고 이러한 핵심 엔터티는 일반적으로 한 고객 또는 다른 고객을 위해 확장 되므로이 핵심 저장소에는 라이브러리를 거의 배치 할 수 없다고 생각합니다. 예를 들어 "고객"엔터티가 정의되어 있고 거의 모든 다른 라이브러리와 프로그램에서 사용되는 하나의 라이브러리에 ORM이 매핑되어 있습니다. 그러나 모든 고객에게는 "고객"에 추가해야 할 추가 필드가 있으므로이 라이브러리를 포크해야하므로 이에 따라 모든 라이브러리를 사용해야합니다.
aKzenT

3
셀 수없이 많은 "ifs"를 피하기위한 아이디어는 의존성 주입을 광범위하게 사용하고 서로 다른 고객을 위해 완전한 모듈을 교환하는 것입니다. 그래도 어떻게 작동하는지 잘 모르겠습니다. 이 접근법은 어떻게 작동 했습니까?
aKzenT

+1, 이것은 기본적으로 이것을 잘 처리 한 프로젝트 경험과 일치합니다. '다른 고객에 대한 ifs'접근 방식을 사용하려는 경우 2 가지 사항 : 1. if (customer1) ...을 수행하지 말고 if (configurationOption1) ...을 수행하고 고객 별 구성 옵션을 갖습니다. 2.하지 마십시오! 구성 별 모듈을 사용하는 것보다 시간의 1 %가 더 나은 (더 이해하기 쉽고 유지 관리하기 쉬운) 옵션 일 수 있습니다.
vaughandroid

@Baqueta : 명확하게 설명하면 구성 옵션 (if) 대신 고객 별 모듈을 사용하는 것이 좋습니다. 고객 대신 기능을 차별화하려는 아이디어가 마음에 듭니다. 따라서이 둘의 조합은 구성 옵션에 의해 제어되는 다양한 "기능 모듈"을 갖습니다. 그런 다음 고객은 일련의 독립 기능 모듈로만 표시됩니다. 나는이 접근법을 많이 좋아하지만 이것을 어떻게 설계 해야할지 모르겠다. DI는 모듈 로딩 및 교환 문제를 해결하지만 고객간에 다른 데이터 모델을 어떻게 관리합니까?
aKzenT

예, 기능별 모듈 및 기능별 고객 구성 / 선택. DI가 이상적입니다. 불행히도 필자는 실질적인 고객 별 사용자 정의 요구 사항을 단일 데이터 라이브러리와 결합 할 필요가 없었기 때문에 많은 도움이 될지 확신 할 수 없습니다 ...
vaughandroid

5

내가 작업 한 프로젝트 중 하나는 많은 제품 릴리스에서 지원되는 여러 플랫폼 (5 개 이상)입니다. 당신이 묘사하고있는 많은 도전들은 비록 약간 다른 방식이지만 우리가 직면 한 것들이었습니다. 우리는 독점적 인 DB를 가지고 있었기 때문에 그 분야에서 같은 유형의 문제는 없었습니다.

우리의 구조는 당신과 비슷하지만 코드를위한 단일 저장소가 있습니다. 플랫폼 별 코드는 코드 트리 내에서 고유 한 프로젝트 폴더로 들어갔습니다. 공통 코드는 속한 계층에 따라 트리 내에 존재했습니다.

빌드중인 플랫폼을 기반으로 조건부 컴파일이있었습니다. 이를 유지하는 것은 다소 번거로운 일이지만 새로운 모듈이 플랫폼 별 계층에 추가 된 경우에만 수행해야했습니다.

모든 코드를 단일 리포지토리에 배치하면 여러 플랫폼과 릴리스에서 동시에 버그를 쉽게 수정할 수 있습니다. 새로운 코드가 관련없는 플랫폼을 깨뜨린 경우 모든 플랫폼이 백스톱 역할을 할 수 있도록 자동화 된 빌드 환경을 갖추 었습니다.

우리는 그것을 막으려 고 노력했지만, 플랫폼이 일반적인 코드에있는 플랫폼 별 버그를 기반으로 수정이 필요한 경우가 있습니다. 모듈을 모호하게 보이게하지 않고 조건부로 컴파일을 재정의 할 수 있다면 먼저해야합니다. 그렇지 않다면, 우리는 모듈을 공통 영역 밖으로 옮기고 플랫폼에 맞게 밀어 넣습니다.

데이터베이스의 경우 플랫폼 별 열 / 수정이있는 몇 개의 테이블이있었습니다. 우리는 테이블의 모든 플랫폼 버전이 기본 수준의 기능을 충족하도록하여 공통 코드가 플랫폼 종속성에 대한 걱정없이이를 참조 할 수 있도록합니다. 플랫폼 별 쿼리 / 조작이 플랫폼 프로젝트 계층으로 푸시되었습니다.

따라서 귀하의 질문에 대답하십시오 :

  1. 많은, 그리고 그것은 내가 함께 일한 최고의 팀 중 하나였습니다. 당시 코드베이스는 약 1M 정도였습니다. 나는 접근 방식을 선택하지 못했지만 꽤 잘 작동했습니다. 뒤늦게도 나는 물건을 다루는 더 좋은 방법을 보지 못했습니다.
  2. 나는 당신이 내 대답에서 언급 한 뉘앙스로 제안한 두 번째 접근법을 권장합니다.
  3. 내가 생각할 수있는 책은 없지만 멀티 플랫폼 개발을 시작으로 연구 할 것입니다.
  4. 강력한 거버넌스를 설치하십시오. 코딩 표준을 준수하는 것이 중요합니다. 이러한 표준을 따르는 것이 관리 및 유지 관리가 가능한 유일한 방법입니다. 우리는 우리가 따르고있는 모델을 깨 뜨리려는 열정적 인 탄원에 대한 우리의 몫을 가졌지 만, 그러한 호소 중 어느 것도 전체 수석 개발팀을 동요 한 적이 없습니다.

경험을 공유해 주셔서 감사합니다. 더 잘 이해하기 위해 : 귀하의 경우에 플랫폼이 어떻게 정의되어 있습니까? Windows, Linux, X86 / x64? 아니면 다른 고객 / 환경과 더 관련이 있습니까? 당신은 4)에서 좋은 지적을하고 있습니다. 나는 그것이 우리가 가진 문제 중 하나라고 생각합니다. 우리는 매우 영리하고 자격을 갖춘 많은 사람들로 구성된 팀을 가지고 있지만 모든 사람은 일을 수행하는 방법에 대해 약간 다른 아이디어를 가지고 있습니다. 아키텍처를 명확하게 담당하는 사람이 없으면 일반적인 전략에 동의하기가 어렵고 아무 것도 변경하지 않고 토론에서 자신을 잃어 버릴 위험이 있습니다.
aKzenT

@ aKzenT-예, 물리적 하드웨어 및 OS를 플랫폼으로 의미했습니다. 우리는 라이센스 모듈로 선택할 수있는 큰 기능 세트를 가지고있었습니다. 그리고 우리는 광범위한 하드웨어를 지원했습니다. 이와 관련하여 우리는 코드 트리를 위해 해당 레이어에 자체 디렉토리가있는 많은 장치가있는 공통 레이어 디렉토리를 가지고있었습니다. 따라서 우리의 상황은 실제로 당신이있는 곳에서 멀지 않은 것은 아닙니다. 우리 선임 개발자들은 서로에 대해 논쟁을 벌였지 만 일단 집단 결정이 내려지면 모든 사람들이 선을 토로하기로 합의했습니다.

4

나는 비슷한 문제가있는 연금 관리 신청서를 수년 동안 일했습니다. 연금 계획은 회사마다 크게 다르며 계산 논리 및 보고서를 구현하기위한 고도의 전문 지식과 매우 다른 데이터 디자인이 필요합니다. 아키텍처의 일부에 대한 간단한 설명 만 제공 할 수 있지만 아이디어가 충분할 수 있습니다.

핵심 시스템 코드 (위의 80 % 공유 코드)를 담당 하는 핵심 개발 팀과 연금 시스템에 대한 도메인 전문 지식을 갖춘 구현 팀, 클라이언트 학습을 담당 하는 2 개의 별도 팀 이 있습니다. 클라이언트에 대한 요구 사항 및 코딩 스크립트 및 보고서

우리는 Xml에 의해 정의 된 모든 테이블을 가지고있었습니다 (이것은 엔티티 프레임 워크가 시간 테스트되고 일반적인 시간이되기 전에) 구현 팀은 Xml의 모든 테이블을 디자인하고 핵심 응용 프로그램은 Xml의 모든 테이블을 생성하라는 메시지를 표시 할 수 있습니다. 각 클라이언트에 대한 관련 VB 스크립트 파일, Crystal Reports, Word 문서 등도 있습니다. (다른 구현을 재사용 할 수 있도록 Xml에 기본 제공되는 상속 모델도있었습니다).

핵심 응용 프로그램 (모든 클라이언트에 대한 하나의 응용 프로그램)은 해당 클라이언트에 대한 요청이 왔을 때 모든 클라이언트 특정 항목을 캐시하고 공통 데이터 개체 (원격 ADO 레코드 세트와 같은 종류)를 생성하여 직렬화 및 전달할 수 있습니다. 약.

이 데이터 모델은 엔터티 / 도메인 개체보다 덜 매끄럽지 만 매우 유연하고 보편적이며 한 세트의 핵심 코드로 처리 할 수 ​​있습니다. 아마도 귀하의 경우 공통 필드만으로 기본 엔티티 객체를 정의하고 사용자 정의 필드에 대한 추가 사전을 가질 수 있습니다 (사용자 정의 필드에 대한 메타 데이터를 갖도록 엔티티 객체에 일종의 데이터 설명자 세트를 추가하십시오). )

핵심 시스템 코드와 구현 코드를위한 별도의 소스 리포지토리가있었습니다.

우리의 핵심 시스템은 실제로 표준 공통 계산 모듈 이외의 비즈니스 로직이 거의 없었습니다. 핵심 시스템은 화면 생성기, 스크립트 실행기, 보고서 생성기, 데이터 액세스 및 전송 계층으로 작동했습니다.

핵심 로직과 맞춤형 로직을 세분화하는 것은 어려운 과제입니다. 그러나 우리는 항상 각 클라이언트에 대해 여러 개의 시스템 사본을 실행하는 대신 하나의 코어 시스템이 여러 개의 클라이언트를 실행하는 것이 더 좋다고 생각했습니다.


피드백 감사드립니다. 사전에 추가 필드가 있다는 아이디어가 마음에 듭니다. 이를 통해 엔티티에 대한 단일 정의를 보유하고 모든 클라이언트 특정 항목을 사전에 넣을 수 있습니다. ORM 래퍼 (Entity Framework)와 함께 작동시키는 좋은 방법이 있는지 확실하지 않습니다. 또한 모든 기능 / 모듈에 대한 모델을 사용하는 대신 전역 적으로 공유되는 데이터 모델을 갖는 것이 좋은 아이디어인지 확실하지 않습니다.
aKzenT

2

나는 더 작은 시스템 (20 kloc)에서 일했으며 DI와 구성이 클라이언트 간의 차이점을 관리하는 훌륭한 방법이지만 시스템을 포크하지 않는 것으로 충분하다는 것을 알았습니다. 데이터베이스는 고정 스키마가있는 응용 프로그램 특정 부분과 사용자 지정 XML 구성 문서를 통해 정의 된 클라이언트 종속 부분으로 분할됩니다.

우리는 단일 지점을 수은으로 제공했는데 마치 마치 배달 가능하도록 구성되었지만 가상의 클라이언트를 위해 브랜드화되고 구성되었습니다. 버그 수정은 해당 프로젝트에 기본으로 제공되며 핵심 기능의 새로운 개발은 여기서 만 발생합니다. 실제 클라이언트에 대한 릴리스는 해당 저장소에서 분리되어 자체 저장소에 저장됩니다. 우리는 수동으로 작성된 버전 번호를 통해 코드의 큰 변화를 추적하고 커밋 번호를 사용하여 버그 수정을 추적합니다.


고객간에 동일한 핵심 라이브러리를 구분 했습니까? 아니면 전체 트리를 분기합니까? 메인 라인에서 개별 포크로 정기적으로 병합합니까? 그렇다면 매일 병합 루틴 비용이 얼마나 오래 걸렸으며 시간 압력이 시작될 때 (이 프로젝트의 한 지점에서 항상 수행하는 것처럼)이 절차가 어떻게 진행되는 것을 피합니까? 너무 많은 질문에 대해 죄송합니다 : p
aKzenT

우리는 전체 트리를 포크합니다. 주로 클라이언트 요청이 빌드 시스템 무결성보다 먼저 이루어지기 때문입니다. 주 시스템에서의 병합은 수은 및 기타 도구를 사용하여 수동으로 수행되며 일반적으로 중요한 버그 또는 대규모 기능 업데이트로 제한됩니다. 우리는 병합 비용과 많은 클라이언트가 자체 시스템을 호스팅하기 때문에 큰 규모의 드문 청크에 대한 업데이트를 유지하려고 노력하며 가치를 제공하지 않고 설치 비용을 지불하고 싶지 않습니다.
Dan Monego

궁금합니다 : IIRC 머큐리얼은 git와 비슷한 DVCS입니다. Subversion 또는 다른 기존 VCS와 비교할 때 브랜치간에 이러한 병합을 수행하면 어떤 이점이 있습니까? 나는 subversion을 사용하여 완전히 분리 된 2 개의 브랜치간에 매우 고통스러운 병합 프로세스를 마쳤으며 git을 사용하면 더 쉬울 것이라고 생각했습니다.
aKzenT

Vault라는 이전 도구를 사용하는 것보다 수은을 사용하는 것이 훨씬 쉽고 쉽습니다. 주요 장점 중 하나는 수은이 변경 이력을 응용 프로그램의 전면과 중앙에 두는 것에서 실제로 우수하므로 어디에서 수행되었는지를 쉽게 추적 할 수 있다는 것입니다. 가장 어려운 부분은 기존 지점을 이전하는 것입니다. 두 지점을 병합하는 경우, 수은은 두 루트가 모두 같아야하므로 설정을 완료하려면 마지막으로 완전히 수동으로 병합해야합니다.
Dan Monego

2

귀하가 설명하는 문제에 대한 직접적인 경험이없는 것이 두렵지 만 의견이 있습니다.

두 번째 옵션은 코드를 중앙 저장소 (실제로 가능한 한)로 모으고 사용자 지정을위한 설계 (실제적으로 가능한 한 많이)는 장기적으로 진행하는 방법입니다.

문제는 당신이 거기에 어떻게 도착할 것인지, 그리고 얼마나 오래 걸릴 것인가입니다.

이 상황에서 한 번에 저장소에 둘 이상의 응용 프로그램 사본이있는 것이 좋습니다.

이를 통해 한 번에 실패하지 않고도 커스터마이징을 직접 지원하는 아키텍처로 점차 이동할 수 있습니다.


2

두 번째 방법은 더 우아해 보이지만이 방법에는 해결되지 않은 많은 문제가 있습니다.

이러한 문제 중 하나라도 하나씩 해결 될 수 있다고 확신합니다. 문제가 발생하면 여기에서 특정 문제에 대해 SO 또는 SO에 문의하십시오.

다른 사람들이 지적했듯이 하나의 중앙 코드베이스 / 하나의 저장소를 갖는 것이 선호하는 옵션입니다. 나는 당신의 모범적 인 질문에 대답하려고 노력합니다.

예 : 모델 / 데이터베이스에서 변경 / 추가를 처리하는 방법 Entity Framework와 함께 .NET을 사용하여 강력한 형식의 엔터티를 갖습니다. 데이터 모델을 어지럽히 지 않고 한 고객에게는 필요하지만 다른 고객에게는 쓸모없는 속성을 처리하는 방법을 알 수 없습니다.

몇 가지 가능성이 있습니다. 모두 실제 시스템에서 보았습니다. 어떤 것을 선택할지는 상황에 따라 다릅니다.

  • 어수선한 상태로 산다
  • "CustomAttributes"(이름 및 유형을 설명하는) 및 "CustomAttributeValues"(예 : 숫자 인 경우에도 문자열 표현으로 저장된 값) 테이블을 소개합니다. 이를 통해 설치시 또는 런타임시 각 고객마다 개별 값을 갖는 속성을 추가 할 수 있습니다. 데이터 모델에서 각 사용자 정의 속성이 "가시적으로"모델링되도록 주장하지 마십시오.

  • 이제 코드에서 그것을 사용하는 방법이 분명해야합니다. 테이블에 액세스하기위한 일반 코드와 해당 속성을 올바르게 해석하기위한 개별 코드 (아마도 별도의 플러그인 DLL에 있음)가 있어야합니다.

  • 또 다른 대안은 각 엔티티 테이블에 개별 XML 문자열을 추가 할 수있는 큰 문자열 필드를 제공하는 것입니다.
  • 일부 개념을 일반화하여 다른 고객에게보다 쉽게 ​​재사용 할 수 있도록하십시오. Martin Fowler의 저서 " 분석 패턴 "을 추천합니다. 이 책은 소프트웨어 사용자 정의에 대한 것이 아니지만 도움이 될 수도 있습니다.

특정 코드의 경우 : 특히 고객 별 스크립트를 추가하기 위해 제품에 스크립팅 언어를 도입 할 수도 있습니다. 이렇게하면 코드와 고객 별 코드를 명확하게 구분할 수있을뿐만 아니라 고객이 시스템을 어느 정도 스스로 사용자 지정할 수 있습니다.


사용자 지정 속성을 저장하기 위해 CustomAttributes 또는 XML 열을 추가 할 때 나타나는 문제는 기능이 매우 제한적이라는 것입니다. 예를 들어 이러한 속성을 기준으로 정렬, 그룹화 또는 필터링을 수행하는 것은 매우 어려운 일입니다. 한 번 추가 속성 테이블을 사용하는 시스템에서 작업 한 결과 이러한 사용자 지정 속성을 유지 관리하는 것이 점점 복잡해졌습니다. 이러한 이유로 나는 이러한 속성을 열에 원래 테이블에 1 : 1로 매핑되는 여분의 테이블에 넣는 대신 생각했습니다. 정의, 쿼리 및 관리 방법에 대한 문제는 여전히 동일합니다.
akzenT

@ aKzenT : 사용자 정의 기능은 무료로 제공되지 않으므로 사용 편의성과 사용자 정의 기능을 교환해야합니다. 필자의 일반적인 제안은 시스템의 핵심 부분이 어떤 방식 으로든 사용자 지정 부분에 의존하는 의존성을 도입하지 않고 다른 방식으로 만 의존한다는 것입니다. 예를 들어 고객 1에 이러한 "추가 테이블"을 도입 할 때 고객 2에 대한 해당 테이블 및 관련 코드를 배포하지 않아도 될까요? 대답이 예라면 해결책은 괜찮습니다.
Doc Brown

0

그런 응용 프로그램을 하나만 만들었습니다. 나는 팔린 단위의 90 %가 그대로 판매되었다고 말하고 싶습니다. 각 고객은 자신의 맞춤형 스킨을 보유하고 있었고 해당 스킨 내에서 시스템을 제공했습니다. 핵심 섹션에 영향을 미치는 모드가 들어 왔을 때 IF 분기를 사용해 보았습니다 . mod # 2가 같은 섹션에 들어 왔을 때 CASE 로직으로 전환하여 향후 확장이 가능했습니다. 이것은 대부분의 사소한 요청을 처리하는 것처럼 보였습니다.

더 작은 사소한 사용자 정의 요청은 Case 로직을 구현하여 처리되었습니다.

모드가 두 개의 급진적이라면 복제본 (별도 포함)을 구축하고 CASE를 감싸서 다른 모듈을 포함시킵니다.

코어의 버그 수정 및 수정은 모든 사용자에게 영향을 미쳤습니다. 우리는 생산에 가기 전에 철저한 개발 테스트를 거쳤습니다. 우리는 항상 변경 사항이 포함 된 이메일 알림을 발송했으며 결코 금요일에 생산 변경 사항을 게시하지 않았습니다.

우리의 환경은 Classic ASP와 SQL Server였습니다. 우리는 스파게티 코드 상점이 아니 었습니다 ... 포함, 서브 루틴 및 기능을 사용하여 모든 것이 모듈화되었습니다.


-1

A와 80 % 기능을 공유하는 B 개발을 시작하라는 요청을 받으면 다음 중 하나를 수행합니다.

  1. A를 복제하고 수정하십시오.
  2. A와 B가 모두 사용할 C로 공유하는 기능을 추출하십시오.
  3. A와 B 자체의 요구를 모두 충족 할 수 있도록 A를 구성 할 수 있도록하십시오 (따라서 B는 A에 포함됨).

1을 선택했는데 상황에 잘 맞지 않는 것 같습니다. 귀하의 임무는 2와 3 중 어느 것이 더 적합한지를 예측하는 것입니다.


1
쉽지만 실제로는 어떻게해야합니까? "if (customer1)"로 어수선하지 않고 소프트웨어를 어떻게 구성 할 수있게합니까?
aKzenT

@aKzenT 그래서 당신이 선택할 수 있도록 2와 3을 남겼습니다. 구성을 통한 customer1의 프로젝트 지원 customer2의 요구를 지원하는 데 필요한 종류의 변경으로 인해 코드를 유지 보수 할 수 없게되면 3을 수행하지 마십시오.
Moshe Revah

"if (customer1)"대신 "if (option1)"을 수행하는 것을 선호합니다. 이 방법으로 N 옵션을 사용하면 가능한 많은 고객을 관리 할 수 ​​있습니다. 예를 들어 N 부울 옵션을 사용하면 2 ^ N 고객 만 관리 할 수 ​​있으며 N 'if'만 있습니다. 2 ^ N 'if'가 필요한 "if (customer1)"전략으로는 관리 할 수 ​​없습니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.