반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

문돌이에서 시작해 어느 새 개발자가 되어버린 베르에 대해서 이야기 해봅시다.

반응형
반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

이번에는 깃허브에 리포지토리를 생성하고 프로젝트를 업로드하는 방법을 알아봅시다.

 

타임라인

0:00 인트로

0:37 깃허브 웹에서 리포지토리 생성하고 프로젝트 업로드하기

4:04 깃허브 웹에서 리포지토리 생성하고 프로젝트 업로드했을 때 주의점

4:53 깃허브 데스크탑 앱에서 리포지토리 생성하고 프로젝트 업로드하기

6:09 아웃트로

반응형
반응형

 

안녕하세요! 여러분들과 함께 게임 개발을 공부하는 베르입니다!

디버그에 대해서 이런 저런 이야기를 해본 스트리밍의 편집본입니다!

 

타임라인

0:00 인트로

1:25 디버그란?

2:23 버그의 유래

5:02 프로그래머의 숙명

5:56 버그를 줄이고 버그를 빨리 찾기 위해서는?

7:42 버그가 발생할 확률을 줄이는 법 1

13:54 버그가 발생할 확률을 줄이는 법 2

16:49 버그가 발생할 확률을 줄이는 법 3

20:17 초보자때 할 수 있는 실수

22:17 버그 리포트

24:38 불필요한 경고문 없애기

26:18 빌드 테스트

28:55 유니티에서 문제 해결하는 법

31:23 베르의 게임 개발 유튜브 멤버십 개발단!

32:14 아웃트로

반응형
반응형

 

여러분들과 함께 게임 개발을 공부하는 베르입니다!

2021년 1월 24일 일요일에 진행한 프로그래밍 & 개발 입문자들이 느끼는 어려움에 대해 이야기하는 스트리밍을 편집한 두 번째 편입니다!

 

타임라인

0:00 QnA2 - 게임 서버는 어떻게 공부했나?

2:20 포트폴리오에 대한 이야기

4:39 개발자의 수준을 결정하는 것들

6:55 QnA3 - 인디 개발자 이야기

7:55 QnA4 - 게임 개발에 필요한 수학 지식?

9:06 QnA5 - 게임 기획?

10:55 QnA6 - 베르가 생각하는 유니티와 언리얼

12:54 QnA7 - 게임 엔진 개발 공부?

14:24 공부할게 너무 많다

15:54 아웃트로

반응형
반응형

 

프로그래밍이나 개발에 처음 입문하는 분들이 느끼는 어려움에 대해서 이야기해봅시다!

 

타임라인

0:00 인트로

0:27 입문자들이 느끼는 어려움 - 머리로 생각한 로직을 코드로 옮기기

2:41 그 해결책?

4:02 베르의 사례

7:10 어려움의 단계를 넘기기 어려운 타입들

16:11 QnA1 - 코드를 짜다가 막혔는데 검색해도 안나올때 or 문서에 함수 이름만 있고 사용법이 잘 안나올 때

20:02 게임 개발 공부 커리큘럼?

23:02 게임 개발 공부할 때 100% 필수인 과목

24:25 게임 개발자의 길

반응형
반응형

 

2021/01/09에 스트리밍으로 진행했던 게임 서버 & 네크워크 개론 편집본입니다!

급하게 기획해서 진행한 스트리밍 강좌라 그런지 아쉬운 점이 많네요. 다음엔 좀 더 잘 준비해서 해보겠습니다. 그리고 아쉬운 소식으로는 지난 1년간 저와 함께 열심히 90여편의 영상을 제작해왔던 마이크가 수명이 다해간다는 겁니다. 그래서 강좌 중간에 사운드가 나간 부분이 많아서 다시 녹음해서 올린 부분이 조금 있습니다. 거기에 무려 한 시간 짜리 영상이라 자막은 언제 제작할 수 있을지 눈 앞이 깜깜하네요 ㅜㅜ

 

타임라인

0:00 인트로

1:00 게임 서버 방식 1 - P2P

3:23 게임 서버 방식 2 - Host

6:31 게임 서버 방식 3 - 데디케이트 서버

8:04 데디케이트 서버를 잘못 만들면?

11:23 장르별 게임 동기화 수준

12:22 FPS/레이싱

13:40 턴제 전략/TCG

13:57 RTS

19:50 게임 네트워크 구조의 변화

27:24 서버 구축 방식의 발전

27:31 전통적인 서버 구축

34:08 IaaS(Infrastructure as a Service)

35:20 Paas(Platform as a Service)

38:31 서버리스 아키텍처

40:30 BaaS(Backend as a Service)

42:33 GBaaS(Game Backend as a Service)

43:44 게임 서버의 궁극! 클라우드 게임

50:06 아웃트로

반응형
반응형

위데브 유튜브 채널 개설!


여러분들과 함께 2-3년간 블로그를 통해서 유니티나 언리얼 엔진 등으로 게임 개발하는 방법을 공부하고 기능들을 소개해온 베르입니다.


이 블로그를 처음 개설한 이유는 인터넷에서 개발과 관련된 자료를 찾아서 공부하고, 나중에 다시 그 자료를 찾으려고 했을 때, 없어진 자료들이 너무나 많아서 느낀 답답함과, 자료를 공유해주신 고마운 분들이지만, 너무 본인 위주의 간략한 설명으로 자료를 따라서 공부하기 어려운 점을 누가 보아도 쉽게 이해할 수 있게 글을 써보자는 욕심이었습니다.


의도한 대로 잘되어 왔는지는 아직 확신할 수는 없지만, 많은 분들이 찾아주신 결과로 현재까지 약 40만여 회의 방문수를 기록하고 있습니다.


하지만, 아직도 아쉬운 점은 게임 개발은 변화가 많고 움직임이 많은 것이기 때문에 순수한 글로써는 제가 의도한 바를 100% 전달하고 있는지 확신할 수 없었습니다. 그래서 처음에는 글에 이미지를 넣고, 이미지에 빨간 박스나 화살표로 강조하는 등의 표시를 해왔고, 개발된 결과로 움직이는 것을 보여드리기 위해서 gif로 찍어서 올리기까지 했습니다.


그렇게까지 해왔지만, 아직은 모자란 점이 많다고 생각하여, 백 번 듣는 것보다는 한 번 보는 것이 났다는 옛 말에 따라 좀 더 확실하게 보여드리고 알려드리기 위해 유튜브 채널을 개설하게 되었습니다.


지난 한 달간 최소한의 콘텐츠를 만들기 위해서 열심히 새로운 영상을 만들고 쌓아온 끝에 드디어 오픈하게 되었습니다.


아직은 기초적인 내용의 영상 밖에 없지만, 지금 블로그에 적힌 다른 포스트 역시 차근차근 영상화해서 찾아뵙겠습니다.


그리고 이 블로그 역시 차근차근 글로 보고 배우는 과정을 따라오시기를 위한 분들을 위해서 업데이트를 계속해서 이어나갈 예정입니다.


위데브 채널 방문하기


위데브 채널에 방문해주셔서 필요한 영상을 시청하시고 좋아요와 구독/알림설정으로 앞으로도 양질의 글과 영상으로 찾아뵐 수 있도록 응원해주세요.


그 동안 이 모자란 블로그에 방문해주시고 사랑해주신 분들께 감사합니다. 그리고 앞으로도 잘 부탁드리겠습니다.



반응형
반응형

읽기 좋은 코드를 위한 간단한 원칙

 

 

 

프로그래머들 사이에선 이런 농담들이 있다.

 

이 코드가 무슨 코드인지는 오직 신과 나만이 안다.

그리고 이제는 오직 신만이 아신다.

 

이게 무슨 의미인가 하면, 작업할 당시에는 내가 아는 코드였지만 시간이 지나면 자신도 본인의 코드를 이해하지 못하게 되는 경우가 있다는 뜻이다. 혼자서 하는 작업도 이럴진데, 타인과 하는 작업은 어떨까? 사람마다 코드 작성 타입은 각양각색이라 다른 사람의 코드를 읽어내기가 몇 배는 더 힘들어진다.

 

특히 혼자서 프로그래밍을 공부하던 사람이 다른 학생와 조별 프로그래밍 과제를 한다거나, 다른 개발자나 협업을 하게 되었을 때 자신의 평소 코딩 스타일과 다른 스타일의 코드를 만나게 되면 격렬한 동공지진을 일으키게 된다. 거기에 주석까지 없다면 혼란은 가중된다.

 

그럼 이제 읽기 좋은 코드를 만들기 위한 고민을 시작해보자.

 

 

코드 블럭 중괄호 스타일 { }

 

프로그래머들 사이에서 가장 뜨겁고 격렬한 이슈인 중괄호 문제부터 들어가보자. 중괄호 스타일 문제는 해외에서는 SVN[각주:1]에 코드 전체가 커밋되었길래 봤더니 중괄호 스타일을 전부 바꾸고 커밋했더라 "작업자를 찾아서 가만두지 않겠다" 라는 밈이 나올 정도이다.

 

이 문제는 크게 두 가지 계파로 나누어지는데 다음과 같다.

 

조건문이나 반복문 아래로 중괄호를 내리는 스타일 :

 

if (bCondition)
{
    // Todo
}
else
{
    // Todo
}

for (int i = 0; i < length; i++)
{
    // Todo
}

while (bCondition)
{
    // Todo
}

 

조건문이나 반복문 옆으로 중괄호를 붙이는 스타일 :

 

if (bCondition) {
    // Todo
} else {
    // Todo
}

for (int i = 0; i < length; i++) {
    // Todo
}

while (bCondition) {
    // Todo
}

 

아래로 중괄호를 내리는 스타일의 경우, 줄 수는 늘어나지만 코드 블럭의 시작과 끝을 명확히 알 수 있다는 장점이 있고, 옆으로 붙이는 스타일은 코드 시작과 끝을 명확하게 보기는 어렵지만 코드의 라인 수가 줄어서 한 눈에 더 많은 코드를 볼 수 있다는 장점이 있다.

 

사실 이 문제는 어떤 것이 옳다라고는 단정내려버리기 어려운 문제이지만, 딱 한 가지 나쁜 경우가 있다. 바로 이 두 가지 스타일을 섞어서 쓰는 것이다. 이 두 가지 스타일을 섞어서 쓰는 경우, 개발자들이 코드 블럭의 시작점을 쉽게 놓치게 되는 경우가 상습적으로 발생할 것이다. 이런 경우가 자주 발생한다면, 조건문이나 반복문 내부에 코드를 넣으려다 밖에다 써버린다든지, 그 반대의 경우가 쉽게 발생하고, 두 스타일을 사용하는 모든 개발자가 함께 고통받는 헬코딩이 열린다.

 

그렇기 때문에 이 중괄호 스타일 문제는 일반적으로 팀 내에서 다수를 차지하는 파의 스타일을 따라가든지, 아니면 프로젝트 관리자가 익숙한 스타일을 따라가게 된다.

 

조건문에 관련해서 중괄호 스타일 문제는 하나 더 있다. 그것은 조건문 내부 코드가 한 줄일 때, 중괄호를 생략하는 스타일이다.

 

if (bCondition)
{
    // Todo
}
else
{
    // Todo
}
if (bCondition)
    // Todo
else
    // Todo

 

컴파일러는 조건문 내부 코드가 한 줄일 때, 중괄호를 생략하는 것을 허용하는데, 다른 스타일은 대부분 취향에 따라 갈리는 것이라 팀의 규칙에 따라 정해진 스타일을 따라가기를 권하지만 이 스타일만큼은 반드시 지양하라고 권하고 싶다.

 

그 판단의 근거는 한 줄 짜리 조건문을 치면서 중괄호 { } 두 번을 안치고 "라인 두 줄을 아꼈다.", "코드 치는 속도가 더 빠르다"는 자그마한 이점을 취하기에는 그로 인해서 발생할 문제의 리스크가 훨씬 크기 때문이다. 이런 스타일은 조건문 내부에 코드를 추가할 일이 발생하면 생략했던 중괄호를 다시 추가해야할 뿐만 아니라, 중괄호를 추가하면서 라인을 이리저리 재정렬해야하는 번거로움이 발생하고, 정말로 기초적인 실수지만 조건문 블럭 안에 들어가야할 코드를 블럭 밖으로 빼버리게 만드는 실수를 일으키게 만드는 경우가 잦다.

 

그리고 이 문제는 신텍스 에러가 아닌 논리적인 버그를 발생시킬 확률이 매우 높으며 발견하기가 굉장히 까다로울 확률이 높다. 앞서 이야기 했듯이 조건문 블럭 안에 들어가야할 코드를 블럭 밖으로 빼버리는 실수는 간단한 실수지만, 인간은 무언가 문제를 찾을 때, 자신이 당연한 곳에서 실수하지 않을 것이라는 가정을 하는 경향이 강하기 때문에 문제를 찾으려고 코드를 훑는 와중에 이 "간단한 실수"를 몇 번이나 스쳐보고 지나갈 확률이 높다. 그리고 문제를 찾다 찾다 못찾아서 코드를 한 줄씩 검토하면서 나아갈 때 결국에 이 문제를 마주치게 된다.

 

 

네이밍 스타일

 

두 번째 이슈는 바로 변수와 함수, 클래스 등의 네이밍 스타일이다. 변수와 함수의 이름은 간단하게는 각 변수와 함수의 구별을 넘어서 무엇을 담는 변수인지, 무슨 일을 처리하는 함수인지를 알려주는 역할을 한다. 프로그래머는 개발을 진행하면서 무수히 많은 변수와 함수, 클래스 등을 만들며, 그 이름을 정해야 한다. 오죽하면 프로그래머의 가장 큰 고민이 변수 이름을 짓는 것이라는 말이 나왔겠는가?

 

절대 하지 말아야할 네이밍 스타일

 

중괄호를 다루는 법은 일반적으로 기호에 가까운 것이라 절대 금지한다라고 할 만한 방법이 크게 없지한 이름 짓기에서는 반드시 금지할 게 있다.

 

무성의한 네이밍

 

int i;
float f;
string a, b, c;
void foo();
bool function();

 

변수나 함수의 이름을 무성의하게 대충 짓는 것은 최악의 행위이다. 앞에서 이야기 했듯이 변수나 함수의 이름은 그 변수가 어떤 값을 담을 것인지, 그 함수가 어떤 작업을 처리할 것인지를 알려주는 역할을 한다. 하지만 대충 지어진 이름은 이 변수나 함수가 어떤 역할을 할 것인지를 명확하게 알 수 없게 만들기 때문에 코드의 흐름을 파악하기 위해서 모든 코드와 주석을 일일이 읽어야만 되게 만들어버린다. 그 코드를 작성한 본인이라고 하더라도 시간이 지나면 코드의 흐름을 까먹게 될 확률이 매우 높기 때문에 유지보수가 어려워지게 만든다. 

 

그리고 기억하라 int i, int j가 허용되는 곳은 반복문의 인덱스로 사용되는 임시 변수뿐이다.

 

혼란스러운 네이밍

 

bool isCantMove;

 

뜻이 모호하거나 혼란스러운 네이밍 역시 피해야 한다. 특히 bool이나 boolean 같은 논리 변수에서 이러한 혼란을 피해야 하는데, 쉽게 혼란이 발생하는 경우는 논리 변수로 부정을 정의하는 경우이다. 위의 bool 변수의 경우 is Can't Move, 움직이지 못하는가? 를 정의하는데 이를 조건문에서 구현할 때는 아래와 같이 된다.

 

if (isCantMove)
{
    // To do
}

if (!isCantMove)
{
    // To do
}

 

이를 해석해보면 위 조건문은 "움직이지 못하는가?"이고 아래 조건문은 "움직이지 못하지 않는가?"가 된다. 이런 식으로 부정 조건을 정의하면 사람이 해석하는 과정에서 실수가 발생할 수 있다.

 

bool isMoveable;

 

이런 문제를 발생시키지 않기 위해서는 예시처럼 is Moveable, 움직일 수 있는가? 라고 정의하는 게 좋으며, 이는 조건문으로 :

 

if (isMoveable)
{
    // To do
}

if (!isMoveable)
{
    // To do
}

 

와 같이 구현되며, "움직일 수 있는가?", "움직이지 못하는가?"와 같이 자연스럽게 해석된다.

 

한글리쉬 네이밍

 

일부 개발자들은 아는 영어 단어가 많지 않거나 필요한 단어를 찾기 힘들다는 이유로 그냥 한국어 단어를 발음이 나는대로 영어로 적어서 변수를 만든다.

 

string juso;
int oNuelNalJja;
string yoil;

 

이러한 네이밍은 뭔가 굉장히 난독화된 코드처럼 보이며, 코드를 읽는 사람이 발음해보기 전에는 무슨 변수인지 알기가 어렵다. 한글 로마자 표기는 생각보다 읽기 어렵고 불편한 방식이다. 차라리 무슨 단어를 써야될지 모르겠다면 시간을 조금 더 써서 영어사전을 뒤져봐라.

 

권장하는 네이밍

 

변수나 함수, 클래스의 이름을 명확하게 짓는 것만으로도 코드의 가독성은 상당히 올라가며 유지보수 역시 쉬워진다.

 

변수 이름

 

변수 이름을 작성할 때는 기본적으로 명사를 사용한다.

 

int num;

 

숫자를 세는 변수를 예로 들어보자. 이러한 변수에는 num이라는 이름이 쉽게 붙여진다.

 

int count;

 

갯수를 세는 변수라면 조금 더 명확하게 count라는 이름을 써보자.

 

int itemCount;

 

여기서 더 명확하게 무엇의 갯수를 세는 변수인가?를 추가하면 itemCount가 된다.

 

public class Item
{
    public int itemCount;
}

 

하지만 역으로 멤버 변수일 때는 또 다르다. Item 클래스에 같은 아이템을 여러 개 가질 수 있다고 했을 때, 같은 아이템의 갯수를 표현하는 itemCount 변수는 어떤가? 적절해보이는가?

 

Item item = new Item();
ShowItemCount(item.itemCount);

 

하지만 실제로 itemCount 변수를 사용할 때는 item.itemCount로 이름이 중복 표현된다.

 

public class Item
{
    public int count;
}

Item item = new Item();
ShowItemCount(item.count);

 

이럴 때는 count라는 이름만 써줘도 무엇의 갯수인지 명확하게 표현된다.

 

List<Item> itemList = new List<Item>();
itemList.Count;

 

이와 같은 맥락으로 C#에서 리스트를 사용할 때도 리스트 안에 들어있는 요소의 갯수를 반환받을 때, Count라고 하지 ListInElementsCount라고 일일이 길게 변수이름을 정하지 않는 것과 같다.

 

함수 이름

 

함수는 기본적으로 어떤 일을 처리하는 행위이기 때문에 함수가 처리하고자 하는 행위를 이름으로 만드는 것이 기본이다. 이름을 짓는 방법은 동사, 동사+명사, 동사+부연 설명 혹은 반대로 명사+동사, 부연 설명+동사 방식으로 지어진다. 이른바 두괄식이냐 미괄식이냐 하는 것인데, 대부분 영미권에서는 동사가 앞으로 오는 두괄식을 선호한다. 선호 이전에도 두괄식이 이 함수가 어떤 행위를 하는지 빠르게 알 수 있기 때문에 보통은 자주 사용된다.

 

void Run(); // 동사 : 실행한다
void MoveToDestination(); // 동사 + 부연설명 : 이동한다 + 목적지로
void AttackEnemy(); // 동사 + 명사 : 공격한다 + 적을

 

클래스 이름

 

클래스 이름 역시 그 클래스 주로 하는 행위에 따라 지어지며 주로 명사로 이름을 짓는다. 게임에서 플레이어를 컨트롤 하는 클래스라면 PlayerController, 입력을 관리하는 클래스라면 InputManager와 같은 방식이다.

 

public class SendData { }

 

다만, 이런 방식으로 클래스가 처리하는 일을 이름으로 짓다보면 실수로 클래스의 이름을 함수 형식으로 짓는 경우들이 있다. 위의 예시처럼 데이터를 보내는 클래스를 정의하려고 할 때, "이 클래스는 데이터를 보내는 역할을 하니까 SendData로 지어야겠다"라고 하는 경우다. SendData라는 이름은 동사+명사의 형태로 클래스 작명법보다는 함수 작명법에 가까운데 클래스는 행위가 아닌 행하는 객체이기 때문에 이러한 동사+명사의 작명법이 어울리지 않으며, 함수와 헷갈릴 가능성이 크다.

 

public class DataSender { }

 

그렇기 때문에 데이터를 보내는 클래스의 이름을 정의하고자 할 때는 위의 예시처럼 이름을 명사화해서 DataSender, 데이터 전송자와 같이 네이밍해주는 것이 좋다. 

 

 

이름 표기법

 

대표적인 이름 표기법

 

중괄호를 다루는 방법에도 여러 가지 방법이 있듯이 변수, 함수, 클래스 이름을 표기하는데도 여러 가지 방법이 있다. 그 중에 대표적인 표기법으로는 카멜 표기법, 파스칼 표기법, 스네이크 표기법이 있다.

 

카멜 표기법(Camel Casing)

 

int itemCount;
float moveDirection;
string errorMessage;

 

카멜 표기법은 변수명으로 사용되는 여러 단어 중에 제일 첫 단어는 소문자로, 그 뒤로 새 단어가 등장할 때마다 그 단어의 첫 문자는 대문자로 표기하는 방법이다. 새로운 단어가 나타날 때마다 대문자가 튀어오르는 모양이 낙타의 등 모양 같다고 해서 카멜 표기법이라고 부른다. 이 방법은 새로운 대문자가 나타날 때마다 끊어 읽으면 되기 때문에 상당히 가독성이 좋은 편에 해당한다.

 

파스칼 표기법(Pascal Casing)

 

int ItemCount;
float MoveDirection;
string ErrorMessage;

 

파스칼 표기법은 카멜 표기법과 비슷하지만 제일 첫 단어의 첫 문자 역시 대문자로 표기한다. 가독성 자체는 카멜 표기법과 비슷하다.

 

스네이크 표기법(Snake Casing)

 

int item_count;
float move_direction;
string error_message;

 

스네이크 표기법은 새 단어마다 언더바( _ )를 삽입하는 형식의 표기법이다. 팟홀 표기법(Pothole Casing)이라고도 불린다. 가독성은 좋은 편에 속하지만 이름이 길어질 수록 넣어야 하는 언더바가 늘어날 뿐만 아니라 언더바를 치는 과정 역시 매우 불편한 면이 많다.

 

그 외의...

 

int nItemCount;
float fMoveDirection;
string strErrorMessage;

 

대표적인 위 세 가지 표기법 이 외에도 여러 가지 표기법이 존재하는데, 변수의 타입을 선행표기하는 헝가리안 표기법(Hungarian Casing)이 있고,

 

int itemcount;
float movedirection;
string errormessage;

 

그냥 모든 문자를 소문자로 표기하는 플레인 표기법(Plain Casing) 역시 존재한다.

 

일반적인 표기법 사용

 

프로그래밍에서 사용되는 표기법은 종류가 매우 다양하다. 하지만 하나의 표기법을 모든 코드 전체에 적용시키는 경우는 없고, 분류에 따라서 적절하게 여러 가지 표기법을 혼합해 사용하는 경우가 대다수이다. 각 분류에 따라 자주 사용되는 표기법은 아래와 같다.

 

클래스와 함수의 이름 표기

 

public class Monster
{
    public void Attack() { }
    public void Move() { }
    public bool FindEnemy() { }
}

 

클래스와 함수의 이름을 표기할 때는 주로 파스칼 표기법을 사용한다. 

 

변수 이름 표기

 

변수 이름의 표기법은 변수의 종류에 따라서 사용하는 방법이 많다.

 

클래스 멤버 변수

 

// Camel Casing
public class Monster
{
    public float moveSpeed;
    public float attackSpeed;
}

// Pascal Casing
public class Monster
{
    public float MoveSpeed;
    public float AttackSpeed;
}

// m_
public class Monster
{
    public float m_moveSpeed;
    public float m_attackSpeed;
}

// _
public class Monster
{
    public float _MoveSpeed;
    public float _AttackSpeed;
}

 

특히 변수에 관련된 쪽에서 표기법이 굉장히 의견이 분분한 편인데, 기본적으로는 카멜 표기법과 파스칼 표기법이 자주 사용되고, 멤버 변수와 다른 매개 변수나 임시 변수와 구분하기 위해 m_나 _를 앞에 붙이는 경우가 많다.

 

함수 매개 변수

 

// 1
public class Monster
{
    public float moveSpeed;
    public void SetMoveSpeed(float moveSpeed) { this.moveSpeed = moveSpeed; }
}

// 2
public class Monster
{
    public float moveSpeed;
    public void SetMoveSpeed(float movespeed) { moveSpeed = movespeed; }
}

// 3
public class Monster
{
    public float moveSpeed;
    public void SetMoveSpeed(float _movespeed) { moveSpeed = _movespeed; }
}

// 4
public class Monster
{
    public float m_moveSpeed;
    public void SetMoveSpeed(float moveSpeed) { m_moveSpeed = moveSpeed; }
}

// 5
public class Monster
{
    public float m_moveSpeed;
    public void SetMoveSpeed(float a_moveSpeed) { m_moveSpeed = a_moveSpeed; }
}

// 6
public class Monster
{
    public float _moveSpeed;
    public void SetMoveSpeed(float moveSpeed) { _moveSpeed = moveSpeed; }
}

 

함수의 매개 변수의 경우 멤버 변수와 이름이 같아서 덮어씌워지는 경우가 많기 때문에 굉장히 많은 방법이 사용된다. 1번 경우처럼 그냥 같은 타입을 사용하고 this 키워드를 사용하는 방법부터, 매개 변수(argument)임을 명시하기 위해서 a_를 붙이는 방법까지 사용되기도 한다. 멤버 변수 표기법과 겹치지 않는 것이 우선이기 때문에 멤버 변수 표기법을 회피한 표기법을 선택한다.

 

함수의 임시 변수

 

public void ChangeMoveSpeed(float movespeed)
{
    float prevSpeed = moveSpeed;
}

 

함수 안에서 생성되는 임시 변수의 표기법은 비교적 자유로운 형태를 띈다. 네이밍 규칙만 정상적으로 지켜지면 알아보기 쉽고, 멤버 변수나 매개 변수와 이름이 겹치지 않게 이름 짓기 쉽기 때문에 표기법에 크게 연연하지 않고 적당하게 작성되는 편이다.

 

 

주석(Comment)

 

프로그래밍을 처음 배울 때 주석을 습관적으로 달도록 배우는 경우가 많다. 하지만 과한 주석이 오히려 가독성을 해치기도 한다.

 

불필요한 주석 쓰기

 

// 아이템 리스트를 아이템 리스트 길이만큼 순회한다.
for (int i = 0; i < itemList.Count; i++ /*반복마다 i에 1을 더한다.*/)
{
    var item = itemList[i]; // 이번 반복 횟수의 아이템을 가져온다.
    if (item.type == ItemType.Equipment) // 아이템의 타입이 장비라면 ...
    {
        // 내구도에 0.9를 곱한다.
        item.duration *= 0.9f; // 아이템의 내구도를 감소시키기 위해서
    }
}

 

위의 예시 코드를 보라. 한 눈에 훑어보기만 해도 알 수 있을것 같은 코드에 매 라인마다 주석을 달아둠으로써 오히려 읽기가 어려워졌다. 주석을 다는 습관은 좋은 것이지만, 불필요한 주석까지 다는 습관이라면 나쁜 것이다.

 

주석을 다는 경우는 최적화 작업이 진행되어서 로직을 한 눈에 읽는 것이 불가능해졌을 때, 어떤 방식으로 코드가 작동하는지를 설명하기 위해 주석을 추가하는 것과, 해당 지점에서 어떤 작업을 해야하는지 To do를 작성하는 경우, 해당 코드를 수정할 때 다른 작업자가 어떤 작업에 유의해야 하는지 등의 경고를 남기는데 사용하는 것으로 한정하는 것이 좋다.

 

그 이외의 경우에는 주석을 최대한 자제하고 코드를 읽는 것으로 프로그램을 이해할 수 있게 클래스, 변수, 함수 이름을 작성하고 코드의 흐름을 적절히 하는 것이 좋다.

 

이전 코드 남겨놓기

 

프로그래머라면 아마 대부분이 어떤 코드에 대해서 수정사항이 발생했을 때, 그 부분을 완전히 지워버리지 않고 주석 처리만 해놓고 새로운 코드를 작성한 경험이 있을 것이다.

 

public class Aim : MonoBehaviour
{
    [SerializeField]
    private Color aimColor;

    [SerializeField]
    private Image aimImage;
    private Camera mainCam;

    private Animator animator;

    private void Awake()
    {
        animator = GetComponent<Animator>();
    }

    public void AimingStart()
    {
        //StartCoroutine(ShowAim());
        animator.SetBool("isAiming", true);
    }

    //private IEnumerator ShowAim()
    //{
    //    float timer = 0f;
    //    while(timer <= 1)
    //    {
    //        timer += Time.deltaTime;
    //        var alpha = Mathf.Lerp(0f, 0.5f, timer);
    //        aimImage.color = new Color(aimColor.r, aimColor.g, aimColor.b, alpha);
    //        yield return null;
    //    }
    //}

    public void Aiming(Vector3 aimStartPos, Vector3 aimDirection, Vector2 aimHit)
    {
        if (mainCam == null)
        {
            mainCam = Camera.main;
        }
        var dist = Vector2.Distance(aimStartPos, aimHit);
        aimImage.pixelsPerUnitMultiplier = dist * 0.3f;
        aimImage.rectTransform.localScale = new Vector3(aimImage.rectTransform.localScale.x, dist);
        aimImage.rectTransform.position = mainCam.WorldToScreenPoint(aimStartPos);
        aimImage.rectTransform.up = aimDirection;
    }

    public void AimingEnd()
    {
        animator.SetBool("isAiming", false);

        //StopAllCoroutines();
        //StartCoroutine(HideAim());
    }

    //private IEnumerator HideAim()
    //{
    //    float timer = 0f;
    //    while (timer <= 1)
    //    {
    //        yield return null;
    //        timer += Time.deltaTime;
    //        var alpha = Mathf.Lerp(aimColor.a, 0f, timer);
    //        aimImage.color = new Color(aimColor.r, aimColor.g, aimColor.b, alpha);
    //    }
    //}
}

 

바로 이 코드처럼 말이다. 이처럼 띄엄띄엄 이전 버전의 코드를 남겨두게 되면 코드를 한 눈에 읽기 힘들어지고, 특히 여러 버전의 코드가 겹겹이 쌓이게 되면 나중에 복구하려고 하는 시점에는 어떤게 어떤 버전인지도 헷갈리게 된다. 만약 이전 버전으로 되돌아가야할 일이 있다면 버전이 바뀔 때마다 SVN같은 버전 관리 툴에 업데이트를 한 뒤, 차라리 롤백을 하라. 혼자서 하는 작업이라 SVN을 쓰기 귀찮은 상황이라도 차라리 귀찮음을 무릅쓰고 SVN을 쓰는 것이 최선이며 차선은 백업 폴더에 버전 별로 백업을 해두고 원본에서는 지난 코드를 지우는게 최선이다.

 

아스키아트

 

가독성을 해치는 것 외에도 쓸데없이 개발 효율을 낮추는 것들도 있다.

 

// ========================================= //
//  ||   /||   //||==\\ //==\\ ==== ||\      //
//  ||  //||  // ||  || ||      ||  ||\\     //
//  || // || //  ||==// ||  ==  ||  || \\    //
//  ||//  ||//   || \\  ||  ||  ||  ||==\\   //
//  ||/   ||/    ||  \\ \\==// ==== ||   \\  //
// ========================================= //

 

개발을 진행하다보면 프로그램을 개발하는 것보다 주석을 아름답게 꾸미는 것에 더 관심이 많아보이는 개발자들이 있다. 이러한 작업을 아스키아트라고 한다. 위 예시는 아주 간단한 아스키아트이다(더 멋진 아스키아트를 그릴 수 있었으나 웹페이지에 여백이 부족해 그리지는 않겠다). 아름답지 않은가? 지금이라도 당장 코드를 꾸미러 가고 싶지 않은가? 로망이란 멋있지만 쓸모없는 것을 가리킨다.

 

/* ------------------------------------------------------------------- *
 * Code Writer :: WERGIA                                               *
 * Last Modifier :: SOMETHING-WHO                                      *
 * Last Modified :: 2019/11/5                                          *
 * Version :: 1.1                                                      *
 * ------------------------------------------------------------------- */

 

코드 파일의 버전과 작성자 수정일자 등을 표시하는 것은 좋다. 나쁜 것은 끝 라인에 붙은 *들이다. 작성자는 완벽한 사각형을 만들었다고 좋아하겠지만 나중에 버전이 바뀌거나 수정자가 바뀌는 경우, 안의 내용을 수정해야 하는데 이 과정에서 마지막 끝 줄의 *은 엉망진창이 될 것은 필연적인 일이다. 이 라인을 맞추는 작업에 수정자가 쓸데없는 시간을 쏟느니 그냥 저 *들을 지워버리는게 낫다.

 


 

읽기 좋은 코드를 작성하기 위한 방법들은 여러 가지가 있지만 그것들이 지향하고자 하는 목표는 모두 같다. 코드의 가독성을 상승시키고 유지보수를 하기 쉽게 만드는 것이다. 개발자는 하나의 코드 스타일에 너무 매몰되지 않아야하고 팀의 협업 시스템에 맞춰 스타일을 변경할 수 있어야 한다. 그러면서도 실수를 최대한 줄일 수 있는 스타일을 유지해야만 한다.

 

  1. 팀 단위로 프로그래밍 작업할 때, 버전을 관리하기 위한 툴 [본문으로]
반응형

+ Recent posts