준비내용
CS/프로그래밍 기초,
1. 객체(Object) 개념
- Object 데이터와 메서드를 하나로 묶은 단위 대부분의 프로그래밍 언어에서 최상위 클래스,
2. 접근제한자
- 퍼블릭 어디서든 접근가능 프라이빗 내부에서만 접근가능 프로텍티드 자녀에서 접근가능,
3. Stack / Queue
선입후출, 선입선출
- 두 자료구조 모두 해당 자료구조에 저장되는 데이터의 삽입과 사용의 순서가 예상되는 경우에 사용하면 시간복잡도를 줄일수있음
4. Array / List / LinkedList 차이,
Array - 배열, 생성될때 크기가 확정됨, 메모리내에서 연속적으로 할당되어 색인이 빠름
List - 내부적으론 배열, 하지만 Pool개념을 도입하여 용량을 초과하면 자동으로 확장 가능하도록 만든것
LinkedList - 몰라
5. 얕은 복사 / 깊은 복사,
- 얕은복사 참조인덱스만 / 복사 깊은복사 값자체를 복사해서 새로운 객체를 생성
6. 힙 / 스택 메모리 구조,
- 스택은 Scope내에서만 할당되며 작고 빠름 (변수/구조체/메서드호출), 크기가 작고 빠름
- 힙은 Scope를 벗어나도 할당이 남아있기때문에 GC가 직접 제거를 해줌, 크기가 크고 느림(모든 참조타입)
7. 다형성,
-하나의 선언으로 다양한 특징의 객체를 다루는것, 즉 코드를 얼마나 유연하게 짜서 작업 능률을 높일수 있는가에 대한 이야기. 대표적으로인터페이스
8. 인터페이스 vs 추상 클래스,
- 인터페이스는 규약, 추상클래스는 구체화되지 않은 객체
인터페이스는 규약이기때문에 값을 지니지 않으며 외부로 노출이 가능한 publi c 메서드의 선언만을 담고 있음.
추상클래스는 구체화되지 않은 객체이기 때문에 내부적으론 클래스와 동일하게 사용이 가능하나 추상클래스 자체로는 생성이 불가능해 팩토리가 동반되지 않으면 되려 결합도를 높이는 경우도 있음
인터페이시는 규약이기때문에 다중상속 OK, 추상클래스는 자체로서 클래스이기때문에 다중상속 불가능
둘 모두 처음부터 설계하거나 추후 확장이 예상되는 리팩토링 단계에서 추출할수도 있음
9. 클래스 vs 구조체, - heap / struct
- 클래스는 객체 참조타입이기에 그자체로 힙에 할당됨, 대입시 참조 공유
- 구조체는 단순히 내부 계층을 지닌 값이기에 스택에 할당됨, 대입시 값 복사
그렇기때문에 단순히 참조만 담는다면 구조체에도 클래스를 담을수 있음
왜 쓰는지에 대한 설명이 부족함
---
D. Unity 엔진 관련 질문,
10. Unity 생명주기,
Awake -> OnEnable -> Start -> (Update) -> OnDisable -> OnDestory
Awake -> OnEnable의 -> Start 순서로 진행
셋다 MonoBehavior에 종속되는 메서드
Awake는 생성과정이기에 기본적인 초기화 과정
OnEnable은 컴포넌트 활성화 직후, 말그대로 활성화 시점에 필요한 메서드나 이벤트 구독처리등을 하는것으로 알고 있음.
Start는 컴포넌트가 일을 시작하는 과정, 기능작동에 필요한 과정
다만 개인적으론 MonoBehavior자체가 굉장히 기능적으로 무거운 클래스라고 알고있으며, 유니티에게 초기화와 작동을 모두 맡기는 것이 굉장히 불편하다고 느꼈기에
1. MonoBehavior의 상속은 정말로 씬내에서 직접 작동이 필요로 하는 클래스에만 상속
2. 다양한 의존성 주입으로 명시적으로 초기화 순서의 보장이 필요한 경우엔 부가적인 초기화 메서드의 생성
3. 이벤트의 구독과 해제는 최대한 실제로 해당 이벤트가 필요한 구간에서만 보장
하는 방식으로 사용을 하고 있음.
11. Update / FixedUpdate / LateUpdate 차이,
Update -> 매프레임마다호출 -> 키입력 혹은 타이머
fixedUpdate -> FixedTimestamp에설정된 값에 따라 해당 간격마다 호출 -> 물리효과 적용으로 사용
LateUpdate -> 모든 Update가 호출된후 마지막, 대부분 특정 오브젝트를 팔로잉 하는 오브젝트에 조작용으로 주로 사용 대표적으로 카메라
12. Time.deltaTime,
- 프레임간의 간격, 물리 조작시에 곱해주면 성능과 무방한 일정한 동작을 보장 가능
13. 데이터 파일 포맷 (CSV / JSON)
- CSV는 세퍼레이터로 쉼표를 사용
- JSON은 세퍼레이터로 {}를 활용 []를 활용하여 배열도 표현가능, 깊은 계층을 표현하기가 CSV에 비해 용이
14. 코루틴과 멀티쓰레딩
메인쓰레드에서 실행되는 작업의 상태를 Continuation으로 저장한뒤(yield를 활용) 컬렉션 순회용 인터페이스인 IEnumerator를 반환하여 메인쓰레드 내에서 비동기 처리를 유사하게 실행시킬수 있는 클래스
실제 비동기처리는 멀티쓰레딩이 전제로 깔린다는점에서 차이가 있으나 유사하게 사용이 가능함.
다만 실제 비동기진행방식이 아니며 메인쓰레드내에서 모든것이 처리된다는 특징때문에 코루틴의 작업이 실행될때는 메인쓰레드가 블로킹됨
때문에 실제로 외부 커넥션(외부 API, data reading, database Connection, I/O)등 응답시간을 보장할수 없거나 UX가 인게임플레이가 멈춰선 안되는 곳에서 코루틴을 활용하면 사용자 경험에 악영향을 줄 수 있음.
때문에 그런 곳에선 async/await를 사용해야하며 코루틴은 응답시간이 명시화되었거나 예상이 가능한 곳, 즉 게임의 전체 흐름이 코루틴을 그대로 따라가도 괜찮은 기능, 즉 메인쓰레드의 멈춤이 자연스러운 게임의 경험으로 이어질수 있는곳에서만 활용해야함
15. GC / 최적화,
- 힙에서 더이상 사용되지 않는 객체를 찾아내서 해제하는과정 이과정에서 프레임드랍이나 GC Spike 발생가능
때문에 자주 사용되는 변수는 최대항 캐싱하며 오브젝트풀링, 굳이 필요없는 객체를 생성하는것, 박싱등을 피해야함
박싱이란 스택에 있던걸 힙으로 올리는 과정, 즉 단순 값이나 참조인덱스를 객체로 변환하거나 제네릭대신 Object를 사용하면 발생
16. DrawCall
- CPU가 GPU에게 렌더링을 요청하는것
드로우콜이 너무 많으면 CPU-GPU간 통신 오버헤드로 느려지므로 배칭, 아틀라스등의 기법이 필요함
17. Canvas 동작 방식,
Q1: Canvas에는 Overlay, Camera, World Space 3가지 모드가 있는데, 각각 언제 쓰나요?
- Overay는 가장 일반적인상황, 사용자의 화면과 일치시킬때, Camera는 카메라랑 캔버스를 일치시킬때 WorldSpace는 캔버스를 게임씬내에 그릴때
Q2: Canvas에서 UI 하나만 바뀌어도 전체 Canvas가 Rebuild 되는 경우가 있는데, 이게 왜 그런가요?
- 기본적인 캔버스의 작동방식
Q3: 그럼 Canvas를 여러 개로 분리하는게 좋나요? 어떤 기준으로 나누나요?
- 개인적으론 캔버스를 2가지 방식으로 나눔, 프리팹 모듈화가 가능하도록 기능 계층별 분리, 동적변경이 예상되는 캔버스 vs 그렇지 않은 캔버스
18. TCP / UDP 차이(네트워크 기초),
- TCP : 속도보다 안정성이 필요한 데이터, 핸드쉐이크과정이 필수적임
- UDP : 안정성보다 속도가 필요한 데이터, UDP쪽은 거의 경험이 없으나 개념적으로 차이는 어느정도 인지를 하고 있음
19. Unity에서 오브젝트 풀링(Object Pooling)을 왜 사용하는지, 그리고 직접 구현한다면 어떻게 설계할 건지 설명
개인적으로 생각하는 리소스 활용에 있어서 보편적으로 생각해도 되는 원칙중 하나가 생성은 비싸고, 활성화는 싸다는 점이다.
오브젝트 풀링도 동일한 결이다.
필요할때마다 직접적으로 메모리할당 및 제거를 요청하는것은 메모리소모가 크다.
그렇기때문에 필요한 오브젝트를 미리 만들어두었다가 필요한만큼 미리 만들어두었다가 필요할때마다 활성화해서 사용하는것. 이게 오브젝트 풀링의 기본적인 원리이다.
특히 유니티에서 잦은 힙 할당 및 해제는 GC를 유발할수 있으며 이는 프레임드랍으로 인한 UX저해를 불러일으킬수 있다.
멀티쓰레딩, I/O커넥션등 리소스소모가 큰 생성작업을 필요로 하는 모든 작업에 적용되는 이야기이다.
개인적으론 오브젝트 풀링은 풀링을 필요로하는 클래스가 직접 필요할것으로 예상되는 객체를 미리 생성해두는식으로만 구현해보았고. 직접적으로 풀링기능을 프로젝트내에서 제네릭하게 활용가능하도록 구현해본적은 없다.
다만 구현의 필요성이 있다면 생성을 요청하는곳에서 생성을 필요로하는갯수와 데이터를 전달한뒤 해당 매니져가 생성된 모든 풀과 내부 객체들을 소유하는 식으로 구현을 할것같다.
20. Unity에서 싱글톤(Singleton) 패턴을 사용하는 경우가 많은데, 싱글톤의 단점과 대안에 대해 설명
개인적으로 굉장히 싫어하는 패턴중 하나이다.
싱글톤이란 결국 특정 기능도메인과, 해당 기능에 종속되는 데이터의 변주가 씬을 구분하지 않고 전역적으로 필요하기때문에 생성되는 DDO컴포넌트이다.
하지만 참 많은 개발자들이 단순히 해당 데이터가 어디에서나 필요하다고 '착각'하기때문에, 또 그런 데이터의 존재여부만을 가지고 싱글톤 클래스를 생성한다.
또한 싱글톤이 전해주는 복잡한 의존성에 대한 직관적인 연결고리는 너무나도 매력적으로 다가온다.
하지만 싱글톤 클래스는 해당 클래스를 사용하는 클래스에서 싱글톤 클래스의 구현 방식 및 초기화 여부를 알기가 어렵다.
때문에 초기화 여부에 따른 세밀한 의존성 주입이 필요로하는 경우에 해결이 복잡해지는 경우가 많다.
또한 클래스자체를 사용하기때문에 지나치게 결합도가 높아 싱글톤 클래스의 수정시 해당 싱글톤을 사용하는 모든 클래스에서의 수정을 요구 한다.
디자인패턴자체의 단점보다는 사용되는 케이스의 대부분이 싱글톤의 정확한 용례와 부작용에 대해 고려하지 않는 경우가 많으며
이에 더해 싱글톤의 정확한 사용처와 부작용을 고려하는것이 난이도가 낮은 것도 아니다.
그렇기때문에 개인적으론 싱글톤을 최대한 배제하고 프로젝트 작업 초기부터 클래스간 의존성을 명확히하는 구조를 설계하는것을 좋아한다.
최상위에 프로젝트에 전역적으로 요구되는 의존성을 소유하는 DDO컴포넌트를 생성해서 해당 컴포넌트를 프로젝트 엔트리포인트로 활용하여 해당 컴포넌트 기반으로 C#클래스는 생성자 MonoBehavior클래스라면 Inject메서드를 생성 및 활용하여 종속성을 해결하는 방식이다.
***모의면접 내용
1. 유니티 생명주기
Awake -> OnEnable -> Start -> (Update) -> OnDisable -> OnDestory
Awake Start 중 초기화는 어디서?
Awake를 주로하는걸로 알고있지만 선호하지않음
그럼 어디서? 초기화메서드 따로 만듬
그럼 차이가 뭐임?
Awake - 생성후 활성화
Start - 활성화후 본격적으로 시작
-> 잘 이해하고 있음
-----------------------------------------------------------------------------
2. Update / LateUpdate 차이
Update - 프레임별로 - 타이머/키입력
Late - 모든 업데이트가 끝난후에 - 팔로잉하는 오브젝트 조작할때 - 대표적으로 카메라
->잘 얘기하긴했는데 Update의 가장 대표적인 얘는 키입력보다는 deltaTime을 활용한 이동
-----------------------------------------------------------------------------
3. Update의 문제는?
프레임별로 실행되기때문에 성능문제가 있을수 있음
다지우고 코루틴, Task로 대체하거나 return문을 최대한 앞으로 땡겨서 씀
4. MonoBehavior 상속 안하는경우는?
- 개인적으론 오히려 Mono를 상속하는 케이스가 더 적음 Mono가 무겁기때문에 단순히 LC메서드가 필요하거나 코루틴이 필요한것만으론 상속 안받음
5. 그럼 어쩔때 상속받음?
- 진짜로 씬내에서 걔가 뭔가 스스로 뭔가를 할게 있을때만 상속시킴
6. 그럼 코루틴은 어케함?
- Task 쓰거나 코루틴 래퍼클래스 구현함
7. Task써본적 있음?
- ㅇㅇ 옛날엔 코루틴 자체를 안쓰려고 했는데 요새는 그 생각은 버림
최근 파베 구현할때. 파베API가 Task기반임
거기에 씬이 동기 로딩방식이라 Task기반 비동기 로딩으로 변경했음
-> 개인적으로는 충분히 납득할만한 답변임. 다만 회사따라서 회사가 유니티 의존성이 높으면 음? 할수도?
-----------------------------------------------------------------------------
6. 드로우콜
CPU가 GPU한테 렌더링해달라고 요청하는거
7. 드로우콜의 문제는?
드로우콜 자체의 문제는 없으나 양이 많으면 문제가될수있음 배칭이나 아틀라스로 드로우콜의 양을 줄이는게 해결법
8. 아틀라스는 뭐임?
비슷한거 묶어서 드로우콜 줄이는거
-> 핵심적인건 뭐 다알고 있음
-----------------------------------------------------------------------------
9. List, Array 차이?
- 배열은 결국 연속된메모리 할당한거, Array는 배열인데 용량 다차면 알아서 늘리도록 한거
10. 어떻게 확장하는지 암?
- ㄴㄴ 모름
-> X2로 확장함
-> 이정도면 충분 다만 LinkedList도 기본지식이니 알아야함. 그리고 결국 배열이고 리스트고 자료구조고 포인터라는게 핵심
-----------------------------------------------------------------------------
11. 클래스 vs 구조체?
- 클래스는 힙에 할당되는거 데이터 + 메서드 같이 있는거, 구조체는 스택에 할당되고 그냥 값만 담은거
12. 그래서 구조체 어쩔때씀?
- 구조체는 단순 값만 컨테이닝하고싶을때
13. 클래스는?
- 메서드랑 데이터 같이 필요하고 안에 포함되는 데이터의 양이 많을때?
-> 아슬아슬했는데 결국 나중에 '구조체는 단순 값만 컨테이닝하고싶을때'를 언급해서 통과
왜 쓰는지를 알아야함 결국 heap vs stack임 개념은 이해하고 있는거 같긴한데 말로 설명할수 있도록 노력하는게 좋음