그의 우려는 많은 클래스가 유지 보수의 악몽으로 이어질 것이라는 점이었습니다. 내 견해로는 그 반대 효과가있을 것이라는 것이 었습니다.
나는 절대적으로 친구의 편이지만, 그것은 우리의 영역과 우리가 다루는 문제와 디자인의 유형, 특히 미래에 어떤 유형의 것들이 변화를 요구할 수 있는지의 문제 일 수 있습니다. 다른 문제, 다른 해결책. 나는 옳고 그름을 믿지 않고 단지 특정 설계 문제를 가장 잘 해결할 수있는 최선의 방법을 찾으려고 노력하는 프로그래머입니다. 나는 게임 엔진과 다르지 않은 VFX에서 일합니다.
그러나 적어도 SOLID를 준수하는 아키텍처 (COM 기반 이었음)라고 부르는 문제에서 어려움을 겪고있는 문제는 다음과 같이 "너무 많은 클래스"또는 "너무 많은 함수"로 요약 될 수 있습니다. 친구가 설명 할 수 있습니다. "너무 많은 상호 작용, 오작동을 일으킬 수있는 많은 장소, 부작용을 일으킬 수있는 너무 많은 장소, 변화가 필요할 수있는 너무 많은 장소, 우리가 생각하는 것을하지 않을 너무 많은 장소 "
우리는 하위 유형의 보트로드에 의해 구현 된 소수의 추상적이고 순수한 인터페이스를 가졌습니다 (ECS 이점에 대해 이야기하면서 왼쪽 아래 주석을 무시 하면서이 다이어그램을 만들었습니다).
모션 인터페이스 또는 장면 노드 인터페이스가 조명, 카메라, 메시, 물리 솔버, 쉐이더, 텍스처, 뼈, 기본 모양, 곡선 등 수백 가지 하위 유형으로 구현 될 수있는 경우 (각각 여러 유형이 있음) ). 그리고 궁극적 인 문제는 실제로 그 디자인이 안정적이지 않다는 것입니다. 우리는 변화하는 요구 사항이 있었고 때로는 인터페이스 자체도 변경해야했으며 200 개의 하위 유형으로 구현 된 추상 인터페이스를 변경하려는 경우 비용이 많이 듭니다. 우리는 그 사이에 추상적 인 기본 클래스를 사용함으로써 그러한 설계 변경 비용을 줄 였지만 여전히 비싸다는 것을 완화하기 시작했습니다.
대안으로 게임 산업에서 일반적으로 사용되는 엔터티 구성 요소 시스템 아키텍처를 살펴보기 시작했습니다. 모든 것이 다음과 같이 바뀌 었습니다.
와우! 그것은 유지 보수성 측면에서 그러한 차이였습니다. 종속성은 더 이상 추상화 를 향한 것이 아니라 데이터 (구성 요소)를 향했습니다 . 그리고 필자의 경우 최소한 변화하는 요구 사항에도 불구하고 설계 측면에서 데이터를 훨씬 더 안정적이고 쉽게 얻을 수있었습니다.
또한 ECS의 엔터티는 상속 대신 컴포지션을 사용하므로 실제로 기능을 포함 할 필요는 없습니다. 그것들은 단지 유사한 "구성 요소의 컨테이너"입니다. 따라서 모션 인터페이스 를 구현 한 200 개의 하위 유형이 모션 구성 요소 (모션과 관련된 데이터 일뿐)를 저장하는 200 개의 엔티티 인스턴스 (별도의 코드가있는 별도 유형이 아님) 로 바뀝니다 . A 는 더 이상 별도의 클래스 / 하위 유형이 아닙니다. 전혀 수업이 아닙니다. 공간의 위치 (움직임)와 점 조명의 특정 속성과 관련된 일부 구성 요소 (데이터)를 결합한 개체의 인스턴스입니다. 이와 관련된 유일한 기능은 시스템 내부에 있습니다.PointLight
RenderSystem
장면 렌더링 방법을 결정하기 위해 장면에서 조명 구성 요소를 찾습니다.
ECS 접근 방식에 따라 요구 사항이 변경됨에 따라 해당 데이터에서 작동하는 하나 또는 두 개의 시스템을 변경하거나 측면에 새로운 시스템을 도입하거나 새로운 데이터가 필요한 경우 새로운 구성 요소를 도입해야하는 경우가 종종있었습니다.
따라서 적어도 내 도메인의 경우 모든 사람에게 해당되는 것은 아니라고 확신합니다. 종속성이 안정성 (자주 변경하지 않아도되는 것)으로 흘러 가기 때문에 훨씬 쉽게 만들었습니다. COM 아키텍처에서는 종속성이 추상화를 향해 균일하게 흐를 때 그렇지 않았습니다. 필자의 경우 가능한 모든 작업보다는 모션에 필요한 데이터를 파악하는 것이 훨씬 쉽습니다. 새로운 요구 사항이 들어 오면 몇 개월 또는 몇 년에 걸쳐 약간 변경되는 경우가 많습니다.
OOP에 일부 또는 모든 SOLID 원칙이 코드를 정리하지 않는 경우가 있습니까?
글쎄, 깨끗한 코드 어떤 사람들은 깨끗한 코드를 SOLID와 동일시하기 때문에 말할 수 없지만 ECS와 마찬가지로 기능에서 데이터를 분리하고 추상화에서 데이터로 종속성을 리디렉션하여 일을 훨씬 쉽게 할 수있는 경우가 있습니다. 데이터가 추상화보다 훨씬 안정적 일 경우 명백한 결합 이유 때문에 변경됩니다. 물론 데이터에 대한 의존성은 불변을 유지하는 것을 어렵게 만들 수 있지만 ECS는 시스템 구성 요소를 사용하여 주어진 유형의 구성 요소에 액세스하는 시스템의 수를 최소화하여이를 최소화하는 경향이 있습니다.
DIP가 제안한 것처럼 종속성이 추상화로 흘러가는 것은 아닙니다. 의존성은 미래의 변화가 필요할 것 같지 않은 것들로 흘러 가야합니다. 그것은 모든 경우에 추상화 일 수도 있고 아닐 수도 있습니다 (확실히 내 것이 아니 었습니다).
- 예, SOLID와 부분적으로 충돌하는 OOP 설계 원칙이 있습니다.
- 예, SOLID와 완전히 충돌하는 OOP 설계 원칙이 있습니다.
ECS가 실제로 OOP의 맛인지 확실하지 않습니다. 어떤 사람들은 그것을 그런 식으로 정의하지만, 결합 특성과 기능 (시스템)과 데이터 (구성 요소)의 분리 및 데이터 캡슐화 부족과 본질적으로 다른 것으로 보입니다. 그것이 OOP의 형태로 간주된다면, 나는 그것이 SOLID (적어도 SRP, 개방 / 폐쇄, liskov 대체 및 DIP의 가장 엄격한 아이디어)와 충돌하는 것으로 생각합니다. 그러나 나는 이것이 사람들이 일반적으로 더 잘 이해할 수있는 OOP 맥락에서 해석 할 수있는 것처럼 SOLID의 가장 근본적인 측면이 적용되지 않을 수있는 사례와 도메인의 합리적인 예라고 생각합니다.
조그마한 수업
친구의 놀랍게도 많은 작은 클래스와 여러 추상화 계층이 포함 된 내 게임 중 하나의 아키텍처를 설명하고있었습니다. 나는 이것이 모든 일에 단일 책임을 부여하고 구성 요소 간의 결합을 완화하는 데 중점을 둔 결과라고 주장했다.
ECS는 나의 견해에 많은 도전과 변화를 주었다. 당신과 마찬가지로, 유지 보수성이라는 아이디어는 가능한 것들에 대한 가장 간단한 구현을 가지고 있다고 생각했습니다. 하나의 클래스 또는 함수를 확대하여 가장 간단하고 간단한 구현을보고 싶을 때 가장 합리적이며, 보이지 않으면 리팩터링하고 더 분해 할 수도 있습니다. 그러나 상대적으로 복잡한 것을 둘 이상으로 나눌 때마다 두 개 이상의 것이 필연적으로 상호 작용해야합니다 (아래 참조). 방법, 또는 외부의 무언가가 그들 모두와 상호 작용해야합니다.
요즘 나는 무언가의 단순성과 얼마나 많은 것들과 필요한 상호 작용 사이에 균형 잡힌 행동이 있다는 것을 알았습니다. ECS의 시스템은 PhysicsSystem
or RenderSystem
또는 or 와 같은 데이터에서 작동하는 사소한 구현으로 다소 무겁습니다 GuiLayoutSystem
. 그러나 복잡한 제품에 필요한 제품이 너무 적기 때문에 전체 코드베이스의 전반적인 동작을 쉽게 뒤로 물러서서 추론 할 수 있습니다. 거기에는 무언가 더 적고 더 큰 클래스 (여전히 논란의 여지가있는 단일 책임을 수행 함)의 측면에 기대는 것이 좋지 않을 수도 있음을 암시 할 수 있습니다. 시스템.
상호 작용
추상화를 사용하여 두 개의 구체적인 객체를 분리 할 수는 있지만 여전히 서로 대화하기 때문에 "커플 링"이 아닌 "상호 작용"(인터랙션 감소는 둘 다 감소를 의미 함)이라고 말합니다. 그들은이 간접적 인 의사 소통 과정에서 여전히 부작용을 일으킬 수 있습니다. 그리고 종종 시스템의 정확성에 대해 추론 할 수있는 능력이 "커플 링"보다 이러한 "상호 작용"과 관련이 있다는 것을 알게되었습니다. 상호 작용을 최소화하면 조감도에서 모든 것을 추론하기가 훨씬 쉬워집니다. 즉, ECS는 전혀 말을하지 않는 것을 의미합니다. 그런 의미에서 ECS는 또한 커플 링이 아닌 "상호 작용"을 최소한의 최소값까지 최소화하는 경향이 있습니다 (적어도 나는
즉, 이것은 적어도 부분적으로 나와 내 개인적인 약점 일 수 있습니다. 나는 거대한 규모의 시스템을 만들고 자신에 대해 자신있게 추론하고, 탐색하고, 예측 가능한 방식으로 어디서나 잠재적으로 원하는 변경을 할 수 있다고 느끼는 가장 큰 장애를 발견했습니다. 부작용. 내가 직접 작성한 코드조차도 수만 개의 LOC에서 수십만 개의 LOC로 수백만 개의 LOC로 갈 때 발생하는 가장 큰 장애물입니다. 무언가가 무엇보다 크롤링 속도를 늦추는 경우 응용 프로그램 상태, 데이터, 부작용 측면에서 무슨 일이 일어나고 있는지 더 이상 이해할 수 없다는 의미입니다. 그것' 시스템이 내 생각에 대한 추론 능력을 넘어서게되면 변화의 전체 영향을 이해할 수 없을 정도로 속도를 늦추는 데 필요한 로봇 시간이 아닙니다. 그리고 상호 작용을 줄이는 것은 상호 작용을 최소한으로 줄이면 가능한 많은 수의 장소를 줄이기 때문에 개인적으로 이러한 것들에 압도 당하지 않고 훨씬 더 많은 기능으로 제품을 더 크게 성장시킬 수있는 가장 효과적인 방법이었습니다. 심지어 응용 프로그램 상태를 변경하고 실질적으로 부작용을 일으킬 수도 있습니다.
이것은 다이어그램의 모든 것이 기능을 가지고 있으며 실제 시나리오는 많은 수의 객체를 가질 것입니다. 이것은 커플 링으로서가 아니라 "상호 작용"다이어그램입니다. 하나 사이에 추상화가 있습니다)
... 시스템에만 기능이있는 여기 (파란색 구성 요소는 이제 데이터 일뿐이며 커플 링 다이어그램입니다) :
SOLID와 더 호환되는 OOP 컨텍스트에서 이러한 이점 중 일부를 구체화하는 방법과 어쩌면 이러한 이점 중 일부를 구상하는 방법이 있지만 아직 디자인과 단어를 아직 찾지 못했습니다. 용어가 OOP와 직접 관련된 모든 것을 던지곤했기 때문에 어렵습니다. 나는 여기에 사람들의 대답을 읽고 그것을 이해하고 나 자신을 공식화하기 위해 최선을 다하려고 노력하고 있지만 ECS의 본질에 대해 매우 흥미로운 점이 있습니다. 사용하지 않는 아키텍처에도 더 광범위하게 적용 할 수 있습니다. 또한이 답변이 ECS 프로모션으로 나오지 않기를 바랍니다. ECS를 설계 한 결과 제 생각이 크게 바뀌었기 때문에 매우 흥미 롭습니다.