[C#] 코딩 컨벤션

Date:     Updated:

카테고리:

태그:

머릿말

이번에 회사 Coding Convention을 정하기 위해 만들어 보았습니다. 여러 선배님들의 원칙들을 참조하여 만들었습니다. 혹시 틀린 부분이나, 더 좋은 방식이 있다면 지적해주시면 감사하겠습니다. 앞으로 공부하며 꾸준히 추가할 예정입니다.

기본 원칙

  1. 가독성을 최우선으로 삼는다.(대부분의 경우 코드는 그 자체가 문서의 역할을 해야 함)
  2. 특별한 이유가 있지 않으면 IDE에서 제안하는 서식을 따른다.
  3. 더 좋은 방법이 있을 시 건의하여 코드 컨벤션을 수정한다.

1. 메인 코딩 표준

1. 클래스와 구조체의 이름은 파스칼 표기법을 따른다.

class GameManager
struct GameData

2. 전역변수/지역변수의 이름은 카멜표기법을 따른다. 또한 항상 초기화를 시켜준다.

private int someInt = 0;
private Object someObject = null;

public void SomeMethod()
{
    int someScopeInt = 0;
    Object someScopeObject = null;
}

3. 단, 함수의 매개변수의 경우 카멜 표기법 앞에 _를 붙여 가독성을 높인다.

public void SomeMethod(int _someParameter)
{

}

4. 메서드 이름은 기본적으로 동사 + 명사의 형태로 짓는다.

public void GetUserId()
{
	
}

5. 단, 단순히 불(bool) 상태를 반환하는 메서드의 동사부분은 최대한 Is,Can,Has,Should를 사용하되 그러는 것이 부자연스러울 경우에는 상태를 나타내는 다른 3인칭 단수형 동사를 사용한다.

public bool IsDead(Player _player);
public bool HasScore(Player _player);
public bool CanMove(Player _player);
public bool ShouldDelete(Player _player);
public bool Exists(Player _player);

6. 상수의 이름은 모두 대문자로 하되, 밑줄로 각 단어를 분리한다.

const int SOME_CONSTANT = 1;

7. 상수로 사용하는 개체형 변수에는 static readonly를 사용한다. 또한, 상수와 같이 변수는 모두 대문자로 하되, 밑줄로각 단어를 분리한다.

public static readonly MyConstClass MY_CONST_OBJECT = new MyConstClass();

8. 초기화 후, 값이 변하지 않는 변수는 readonly로 선언한다.

public class Account
 {
     private readonly string password;
    
     public Account(string _password)
     {
         password = _password;
     }
 }

9. 네임스페이스의 이름은 파스칼 표기법을 따른다.

namespace System.Graphics

10. 불(bool) 변수 앞에는 최대한 Is,Can,Has,Should를 사용하되 그러는 것이 부자연스러울 경우에는 상태를 나타내는 다른 3인칭 단수형 동사를 사용한다.

private bool isFired = false;
private bool hasScore = false;

11. 인터페이스를 선언할 때는 앞에 I를 붙인다.

public interface ISomeInterFace;

12. 열거형을 선언할 때는 Cammel Case를 사용한다.

public enum LanguageType
{
	Korea,
	English,
	Japanese
}

13. private 멤버 변수명은 카멜 케이스로 표기하고, public프로퍼티는 파스칼 케이스로 표기한다.

public class User
{
	private int userCode;
	public int UserCode {get; set;}
}

14. 값을 반환하는 함수의 이름은 무엇을 반환하는지 알 수 있게 짓는다.

public string GetUserCode();

15. 단순히 반복문에 사용되는 변수가 아닌 경우에, i, a같은 변수명 대신 index, ant 처럼 변수에 저장되는 데이터를 단번에 알 수있는 변수명을 사용한다.

for(int ant = 0; ant < antsArray.Length; ++ant){}

16. 줄임말은 모두 한 단어처럼 첫글자만 대문자로 표기한다. 단, 첫글자만 대문자로 했을 때, 그 뜻을 이해하기 어렵다면, 예외를 적용한다.

public int UserId {get; set;}
public int UserPassword {get; set;}
public int BgmNumber{get;set;}

17. 프로퍼티를 사용하는것 보다 Getter/Setter를 선호한다. 단, Getter/Setter 로 표현하는것 보다 프로퍼티로 표현하는것이 가독성이 높을 경우 프로퍼티를 사용한다.

public int Age
{
	get
	{
		if(age != 0 )
		{
			return age
		}
	}
	set
	{
		if(age < 10)
		{
			age = value;
		}
	}
}

public void GetAge()
{
	//DBConnection
	//Auth검사 로직
	return age;
}

18. double이 반드시 필요한 경우가 아닌 이상 부동 소수점 값에 f를 붙여준다.

private float f = 0.5f;

19. switch 문에 언제나 default: 케이스를 넣는다.

switch(level)
{
	case 0: 
	//...
	break;
	
	default:
	break;
}

20. switch문 안에서 default 케이스가 절대 실행될 일이 없다고 판단한 경우, default 안에 Debug.Fail()을 추가한다.

switch(level)
{
	case 0: 
	//...
	break;
	
	default:
	Debug.Fail("unknown type");
	break;
}

21. 클래스 안에서 멤버 변수와 메서드의 등장 순서는 다음을 따른다.

  1. 멤버 변수
  2. 프로퍼티
  3. 생성자
  4. 메서드(public -> private 순서로)
private int age = 0;
public int Age {get; set;}

private bool isDead = 0;
public Bool IsDead {get; set;}

public void SetDelegate(){}
private void MomvePlayer(){}

22. 클래스에서 연관 있는 메서드끼리 그룹을 짓는다. 멤버 변수도 마찬가지 이다. 단, 분류가 어려울 경우 예외를 적용한다.

//사용자 정보
private int age = 0;
private string name = "name";

//이동관련 변수
private float moveSpeed = 0f;
private float moveDampling = 0f;

//정보관련 로직
private void AddAge(){}
private void Rename(){}

//플레이어 움직임 
private void Move(){}

23. 매개변수 자료형이 범용적인 경우, 함수 오버로딩을 피한다.

  • 올바른 예
public Anim GetAnimByIndex(int _index){}
public Anim GetAnimByName(){}
  • 틀린 예
public Anim GetAnimBy(int _index){}
public Anim GetAnimBy(string _name){}

24. 클래스는 각각 독립된 파일에 있어야 한다. 단, 작은 클래스 몇 개를 한 파일 안에 같이 넣어두는 것이 상식적일 경우, 예외를 허용한다.

25. 파일 이름은 대소문자까지 포함해서 반드시 클래스 이름과 일치해야 한다. 또한, 특별한 경우가 아닌 이상, 한 파일에는 하나의 클래스만 존재하도록 한다.

🗅 GameManager.cs

public class GameManager()
{

}

26. 비트 플래그 열거형은 이름 뒤에 Flags를 붙인다.

 [Flags]
 public enum EVisibilityFlags
 {
     None = 0,
     Character = 1 << 0,
     Terrain = 1 << 1,
     Building = 1 << 2,
 }

27. 디폴트 매개변수 대신 함수 오버로딩을 선호한다.

  • 틀린 예
public void LogMessage(string _message, LogLevel _level = LogLevel.Info) { // 로그 메시지와 로그 레벨을 출력 }
  • 올바른 예
public void LogMessage(string message) 
{ 
	LogMessage(message, LogLevel.Info); 
} 
public void LogMessage(string message, LogLevel level) 
{
	// 로그 메시지와 로그 레벨을 출력 
}

28. var키워드를 사용하지 않는다. 단, 데이터형이 중요하지않은 경우에는 예외를 허용 한다. IEnumerablevar를 사용하거나, 익명타입(anonymous type)을 사용할 때가 좋은 예이다.

29.async void 대신에 async Task를 사용한다. async void가 허용되는 유일한 곳은 이벤트 핸들러 이다.

30. 외부로부터 들어오는 데이터의 유효성은 외부/내부 경계가 바뀌는 곳에서 검증하고 문제가 있을 경우 내부 함수로 전달하기 전에 반환해 버린다. 즉 경계를 넘어 내부로 들어온 모든 데이터는 유요하다고 가정한다는 것이다.

private void InitPlayer(Player _player)
{
	if(_player == null) return;
}

31. 따라서 내부 함수에서 예외를 던지지 않으려고 노력한다. 예외는 경계에서만 처리하는 것을 원칙으로 한다. 단, 위에서 정의 했듯이, switch문의 default 케이스는 예외로 한다.

32. 함수의 매개변수로 null 을 허용하지 않는 것을 추구한다. 특히, public 함수일 때 더욱 그러하다.

33. 하지만, null을 사용해야 하는 상황이면, 매개변수의 이름 뒤에 OrNull을 붙인다.

public string GetName(string _nameOrNull){}

34. 함수에 전달하는 out 매개변수는 별도의 라인에 선언한다. 즉, 인자 목록 안에서 선언하지 않는다.

35. using선언의 사용을 금지한다. 대신 using문을 사용한다.

  • 틀린 예
using Ant ant = new Ant();
  • 올바른 예
using(Ant ant = new Ant())
{

}

2. 소스 코드 포맷팅

1. 탭(tab)은 비주얼 스튜디오 기본값을 사용하며, 그 외에 띄어쓰기 4칸을 탭으로 사용한다.

2. 중괄호 {} 를 열때는 언제나 새로운 줄에 연다.

3. 한 줄에 변수 하나만 선언한다.

  • 틀린 예
private int cnt, idx = 0;
  • 올바른 예
private int cnt = 0;
private int idx = 0;

C Sharp 카테고리 내 다른 글 보러가기

댓글 남기기