디커플링
결국 컴파일러와 링커의 특성에 대한 뉘앙스가없는 가장 근본적인 디자인 수준에서 하루가 끝나면 나에게 분리하는 것입니다. 나는 각 헤더가 하나의 클래스를 정의하게하고, pimpl을 사용하고, 선언 해야하는 유형으로 선언을 전달하고, 정의되지 않고, 선언을 포함하는 헤더를 사용할 수도 있습니다 (예 :), <iosfwd>
소스 파일 당 하나의 헤더 선언 / 정의 된 것의 유형 등에 따라 시스템을 일관되게 구성하십시오.
"컴파일 타임 종속성"을 줄이는 기술
또한 일부 기술은 상당히 도움이 될 수 있지만 이러한 방법을 모두 사용하면서도 시스템의 평균 소스 파일은 2 페이지의 프리앰블이 필요하다는 것을 알 수 있습니다. #include
인터페이스 디자인에서 논리적 종속성을 줄이지 않고 헤더 수준에서 컴파일 시간 종속성을 줄이는 데 너무 많은 초점을두면 "스파게티 헤더"로 간주되지 않을 수 있습니다. 여전히 실제 생산성과 유사한 해로운 문제로 해석된다고한다. 하루가 끝날 무렵 컴파일 단위에 여전히 많은 양의 정보가 표시되어 무언가를 수행 해야하는 경우 빌드 시간이 길어지고 개발자를 만드는 동안 잠재적으로 돌아가서 변경 해야하는 이유가 배가됩니다. 매일 코딩을 끝내려고 시스템을 방해하는 것처럼 느껴집니다. 그것'
예를 들어, 각 서브 시스템이 하나의 매우 추상적 인 헤더 파일과 인터페이스를 제공하게 할 수 있습니다. 그러나 서브 시스템이 서로 분리되어 있지 않으면 작동하기 위해 혼란스러워 보이는 종속성 그래프가있는 다른 서브 시스템 인터페이스에 따라 서브 시스템 인터페이스와 다시 스파게티를 닮은 것을 얻게됩니다.
외부 유형으로 선언 전달
개발자가 빌드 서버에서 CI 전환을 위해 2 일을 기다리는 동안 2 시간이 걸렸던 이전 코드베이스를 얻으려고 노력한 모든 기술 중에서 (빌드 머신이 열렬한 노력의 짐승이라고 생각할 수 있음) 개발자가 변경 사항을 푸시하는 동안 계속 실패하면) 다른 질문에 정의 된 형식을 선언하는 것이 가장 의문이었습니다. 그리고 코드베이스를 40 분 정도 줄이려고했지만, 조금씩 단계적으로이 작업을 수행 한 후 뒷받침에서 가장 의심스러운 "헤더 스파게티"를 줄이려고 노력했습니다. 터널 상호 의존성에 대한 터널 비전을 고려한 설계)는 다른 헤더에 정의 된 형식을 선언하는 것입니다.
Foo.hpp
다음과 같은 헤더 를 상상하면 :
#include "Bar.hpp"
그리고 그것은 Bar
정의가 아닌 선언이 필요한 방식으로 만 헤더에 사용 합니다. 헤더에 class Bar;
정의가 Bar
표시 되지 않도록 선언 하는 것은 쉬운 일 이 아닙니다 . 실제로는 종종 사용 Foo.hpp
하지만 대부분의 컴파일 단위는 여전히 자신 Bar
을 포함 해야하는 추가 부담으로 정의 해야 할 필요 가 있거나 실제로 도움이되는 다른 시나리오를 실행합니다. 컴파일 단위의 %는 포함하지 않고 작동 할 수 있습니다 . 단, 다음 과 같은 선언문을 볼 필요가있는 이유와 이유에 대한보다 근본적인 디자인 질문 (또는 적어도 요즘은 생각합니다)을 제기합니다.Bar.hpp
Foo.hpp
Bar.hpp
Bar
Foo
대부분의 유스 케이스와 관련이없는 경우 그것에 대해 알고 귀찮게해야합니다 (왜 거의 사용하지 않은 다른 것에 의존하는 디자인에 부담을 주어야합니까?).
개념적으로하기 때문에 우리가 정말 분리하지 않은 Foo
에서 Bar
. 우리는 방금 헤더가 Foo
에 대한 헤더 정보를 많이 필요로하지 않도록 만들었습니다. Bar
이 두 가지를 완전히 독립적으로 만드는 디자인만큼 중요하지는 않습니다.
임베디드 스크립팅
이것은 실제로 더 큰 규모의 코드베이스를위한 것이지만, 내가 유용하게 생각하는 또 다른 기술은 적어도 시스템의 가장 높은 수준의 부분에 대해 임베디드 스크립팅 언어를 사용하는 것입니다. 나는 하루에 Lua를 포함시킬 수 있었고 시스템의 모든 명령을 균일하게 호출 할 수 있음을 알았습니다 (명령은 추상적이었습니다). 불행히도 나는 개발자들이 다른 언어의 도입을 거부하고 가장 기괴하게도 가장 큰 의혹으로 성능을 발휘하는 장애물에 부딪쳤다. 그러나 다른 관심사를 이해할 수는 있지만 사용자가 버튼을 클릭 할 때 명령을 호출하기 위해 스크립트를 사용하는 경우에만 성능이 문제가되지 않아야합니다. 버튼 클릭에 대한 응답 시간의 나노초 차이에 대해 걱정하십니까?).
예
한편 내가 큰 코드베이스에서 컴파일 시간을 단축하는 기술을 소진 한 후 목격 한 가장 효과적인 방법은 아키텍처입니다 진정으로 작업에 시스템의 모든 한 가지에 필요한 정보의 양을 줄이고, 그냥 컴파일러에서 서로 하나의 헤더를 감하지 (인간과 컴파일러의 관점에서 볼 때 컴파일러 종속성을 넘어서는 진정한 분리) 최소한의 인터페이스를 알고 있어야합니다.
ECS는 단지 하나의 예일뿐입니다 (하지만 나는 당신이 하나를 사용하라고 제안하지는 않습니다). 그러나 그것을 만나면 ECS가 자연은 시스템이 ECS 데이터베이스에 대해서만 알고 있으면되고 일반적으로 소수의 구성 요소 유형 (때로는 하나만)만으로도 매우 분리 된 아키텍처를 만듭니다.
디자인, 디자인, 디자인
그리고 이러한 종류의 분리 된 건축 설계는 사람의 개념적 수준에서 코드베이스가 성장하고 성장함에 따라 위에서 살펴본 기술보다 컴파일 시간을 최소화하는 데 더 효과적입니다. 컴파일 유닛은 컴파일 및 링크 타임에 필요한 양의 정보를 곱한 것 ). 또한 빌드 시간 단축 및 헤더 풀림 해제보다 더 많은 이점이 있습니다. 이는 개발자가 무언가를 수행하기 위해 즉시 필요한 것 이상으로 시스템에 대해 많이 알 필요가 없기 때문입니다.
예를 들어, 수백만의 LOC를 포괄하는 AAA 게임을위한 물리 엔진을 개발하기 위해 전문 물리 개발자를 고용 할 수 있고 사용 가능한 유형 및 인터페이스와 같은 절대적인 최소 정보를 알고 있으면서도 매우 빠르게 시작할 수 있습니다. 시스템 개념뿐만 아니라 자연스럽게 그와 컴파일러 모두 물리 엔진을 빌드하는 데 필요한 정보의 양을 줄이며, 일반적으로 스파게티와 유사한 것은 없다는 것을 암시하면서 빌드 시간을 크게 줄입니다. 시스템의 어느 곳에서나 이것이 바로 다른 모든 기술보다 우선 순위를 정할 것을 제안하는 것입니다 : 시스템 설계 방법. 다른 기술을 소진하면 그 위에 있으면 그 위에 착빙됩니다.