바람직한 유니티 코딩방법 (Good Coding Practices in Unity) – 번역

바람직한 유니티 코딩방법 (Good Coding Practices in Unity) – 번역

원문 링크

 

유니티를 새로 시작한 개발자들 중 다수가 고민하지 않지만 여전히 매우 중요한 주제입니다. 그 주제는 바로 코딩 방법에 대한 것이며, 여러분의 삶을 좀 더 쉽게 만들어줄 수도 있습니다.

코딩 방법은 여러분이 코드를 작성할 때 일련의 지침을 두고 코드를 작성하도록 하는 것에 그 목적이 있습니다.
이 지침은 유지보수가 쉽고, 확장 가능하며, 읽기 쉬운 상태로 코드를유지하도록 설계되어, 리팩토링(refactoring)의 고통을 줄이는 데 도움을 줍니다.

프로젝트를 진행하면서 코드를 변경하고 싶었던 적이 얼마나 있었습니까? 그런데 여러분이 변경하려고했던 그 코드에 의존하는 클래스가 너무 많아서 생각했던 것보다 훨씬 힘들었던 적이 있습니까?
– 이것은 마치, 단지 컴퓨터 본체에서 키보드만 분리하려고 본체 뒷면을 봤더니 케이블이 너저분하게 연결되어 있어서 어떤 것이 키보드 케이블인지 구분이 되지않아 공포감마저 느끼게되는 경우와 같습니다. (본문의 내용을 번역했는데, 유머인거 같은데 그다지 공감이 가지는 않네요.)

여기, 케이블을 풀지않고 정리할 수 있도록 도와줄 몇가지 가이드라인이 있습니다.

 

단일 책임 (Single Responsibility)

하나의 클래스는 하나의 작업만 담당하도록 하는 것이 이상적입니다.

단일 책임(Single Responsibility)의 기본 개념은, 각 클래스는 각자가 맡은 작은 작업을 수행하고 이런 작은 작업들을 결합해서 큰 문제를 해결할 수 있다는 것입니다.
지금 이 설명이 컴포넌트를 설명하고 있다고 느껴진다면, 그것은 컴포넌트와 단일 책임의 개념, 이 둘의 개념이 완벽하게 일치하기 때문입니다.

유니티는 재사용이 가능한 작은 단위로 기능을 분리하는데 중점을 두어 설계되었고, 단일 책임(Single Responsibility)은 아마도 이 글에서 제시할 가장 중요한 원칙이 될 것입니다.

이 원칙의 예를 들기 위해, Player 클래스가 있다고 가정해보겠습니다. 플레이어 클래스는 입력, 물리, 무기, 체력, 인벤토리를 처리합니다.

이 기능들은 플레이어가 모두 담당 하기에는 너무 긴 목록입니다.
따라서 각각 하나의 작업을 처리하는 여러 개의 컴포넌트로 분리해야 합니다.

– PlayerInput – 입력 처리 담당
– PlayerPhysics – 물리 시뮬레이션 처리 담당
– WeaponManager – 플레이어의 무기 관리 담당
– Health – 플레이어의 체력 담당
– PlayerInventory – 플레이어의 인벤토리 관리 담당

아, 이제 한결 나아졌습니다. 하지만, 이 클래스들은 서로 크게 의존하고있기 때문에 여전히 문제를 가지고 있습니다. 이제 이 문제를 해결해보겠습니다.

 

의존성 전도 (Dependency Inversion)

특정 클래스가 다른 클래스를 의존하는 경우, 그 의존 관계를 추상화합니다.

의존성 전도(Dependency Inversion)의 기본 개념은,클래스간의 의존성(Dependency)을 없애기 위해서, 특정 클래스가 다른 클래스를 호출할 때마다 해당 호출을 일종의 추상화로 대체해야한다는 것입니다.

클래스 의존성을 인터페이스(Interface)로 대체하는 것이 가장 바람직합니다.
따라서 클래스 A에서 클래스 B의 메소드를 직접 호출하는 대신, 클래스 B가 구현한 인터페이스인 ISomeInterface의 메소드를 클래스 A에서 호출하도록 하는 것이 좋습니다.

다른 방법은 클래스 B가 상속받는 추상클래스를 설계하는 것입니다.
따라서 클래스 A는 클래스 B에 직접 의존(접근)해서 사용하는 대신, 클래스 B를 클래스 B가 상속받은 추상클래스로 취급하도록 하는 것입니다.

물론, 가장 안좋은 방법은 클래스 A가 클래스 B를 직접 의존하도록 하는 것입니다. 이것이 바로 우리가 피해야하는 방법입니다.

따라서 앞의 예제에서의 컴포넌트들은 서로 매우 밀접하게 연결되어있습니다(의존성이 높습니다).
PlayerInput은 아마 PlayerPhysics의 존재에 의존할 가능성이 높고, WeaponManager는 Inventory에 의존할 가능성이 매우 높습니다.

따라서 이런 의존 관계를 추상화해야 합니다.

– IActorPhysics – 입력을 받아서 물리 시뮬레이션에 영향을 줄 수있는 클래스를 위한 인터페이스
– IDamageable – 데미지를 처리할 수있는 클래스를 위한 인터페이스
– IInventory – 아이템을 저장하고 사용할 수있는 클래스를 위한 인터페이스

이제 PlayerPhysics 클래스에서 IActorPhysics 인터페이스를 구현하고, Health 클래스에서 IDamageable 인터페이스를 구현하고, PlayerInventory 클래스에서 IInventory 인터페이스를 구현하도록 합니다.

그러면 PlayerInput 클래스는 IActorPhysics 인터페이스에만 의존하게 되고, WeaponManager 클래스는 IInventory 인터페이스에만 의존하게 되며, 플레이어의 데미지를 처리하는 클래스는 IDamageable 인터페이스와 의존성이 성립됩니다. 따라서 클래스간의 의존성이 사라집니다.

의존성 전도(Dependency Inversion)는 단일 책임(Single Responsibility)을 강화하는데 어느정도 도움이 됩니다.

예를 들어, PlayerInput 클래스는 플레이어가 어떻게 움직이는지 여부와 어떤 방식으로 플레이어를 움직일지 여부는 신경쓰지 않도록 해야합니다.
단지 클래스가 맡은 기능만 담당할 수 있도록 설계하는 것입니다.

알아두면 좋은 것 중 하나는, 몇몇 경우에서 SendMessage를 이용하면 동일한 목표를 달성할 수 있다는 점입니다.

 

 

모듈화 (Modularization)

개인적으로, 유니티에서 아래와 같은 코드를 많이 봐왔습니다.

switch( behavior )
{
    case 1: // some behavior
    case 2: // another behavior
    case 3: // yet another behavior
    case 4: // the last behavior
}

 

물론 위의 코드도 잘 동작하지만, 더 좋은 방식으로 코드를 구성할 수 있습니다. 이 코드는 사실 모듈화(Modularization)를 해달라고 비명을 지르고 있습니다.

각 상황에 따라서 실행되는 Behavior들은 모듈(module)이 되고, switch  구문에 조건으로 사용된 “behavior”는 열거형이거나 특정 모듈의 인스턴스일 것입니다. (이 경우, 해당 모듈이 클래스 또는 구조체라고 보기쉽다 하더라도, 해당 모듈을 딜리게이트(delegate)라고 가정하겠습니다.)

그러면, 위의 코드는 아래와 같이 바꿀 수 있습니다.

behavior();

 

그리고 다른 곳에서 현재의 모듈을 아래 코드와 같이 할당할 수 있습니다.

MyClass.behavior = someBehavior;

 

아마 someBehavior가 함수일 것 같습니다. (또는 위에서 할당한 모듈이 클래스라면, someBehavior는 클래스의 인스턴스일 것입니다.)

이렇게 모듈화하는 방법은 특히 상태머신(state machine)과 같은 시스템을 만들거나 메뉴 시스템을 만들때 매우 유용합니다.
사용가능한 모든 상태나 모든 메뉴에 대한 값을 갖는  열거형을 정의할 수는 있습니다. 하지만, 해당 상태와 메뉴를 모듈로 만들어서 교환해가면서 사용하도록 설계하는 것이 바람직합니다.

이렇게 모듈로 설계하게되면, 상태나 메뉴를 추가할때마다 열거형을 추가하고, switch case 구문을 확장할 필요가 없습니다.

 

결론 (Conclusion)

이 글에서 소개한 방법만이 유일한 코딩방법은 아닙니다. 하지만, 이 방법들은 따라서 적용하기에 매우 유용한 가이드라인 입니다.
여러분이 항상 이 지침을 따라야 하는것은 아닙니다. (이 규칙들은 때때로 적용하기 힘들고, 너무 이상적일 때가 있습니다.)

하지만, 비판적으로 생각해보면서 여러분의 코드에 적용하면 얻을 수 있는 이점이 없는지 고려해보는 것이 좋습니다.

명심해야할 것은, 이 지침을 활용한다고해서 지금 당장 여러분의 코드 한줄을 줄여주지는 않지만, 이 지침들이 나중에 다가올 두통을 피할 수 있는 방법이라는 것입니다.

 

 

내용 끝까지 읽어주셔서 감사합니다.

배너 클릭은 저에게 많은 힘이 됩니다.

감사합니다 🙂

 

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, C++/C#, 1인 기업에 관심이 많습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Please turn AdBlock off

Notice for AdBlock users

Please turn AdBlock off