[C#] 코딩 컨벤션
카테고리: C Sharp
머릿말
이번에 회사 Coding Convention을 정하기 위해 만들어 보았습니다. 여러 선배님들의 원칙들을 참조하여 만들었습니다. 혹시 틀린 부분이나, 더 좋은 방식이 있다면 지적해주시면 감사하겠습니다. 앞으로 공부하며 꾸준히 추가할 예정입니다.
기본 원칙
- 가독성을 최우선으로 삼는다.(대부분의 경우 코드는 그 자체가 문서의 역할을 해야 함)
- 특별한 이유가 있지 않으면 IDE에서 제안하는 서식을 따른다.
- 더 좋은 방법이 있을 시 건의하여 코드 컨벤션을 수정한다.
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. 클래스 안에서 멤버 변수와 메서드의 등장 순서는 다음을 따른다.
- 멤버 변수
- 프로퍼티
- 생성자
- 메서드(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
키워드를 사용하지 않는다. 단, 데이터형이 중요하지않은 경우에는 예외를 허용 한다. IEnumerable
에 var
를 사용하거나, 익명타입(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;
댓글 남기기