POCU 아카데미용 C# 코딩 표준
본 코딩 표준은 Pope Kim의 C# 코딩 표준을 POCU 아카데미에 적합하게 수정한 것입니다. 취소선(취소선) 표시가 된 항목들은 무시해주세요.
- 원문(영어): C# Coding Standards
머리말
기본 원칙
- 가독성을 최우선으로 삼는다. (대부분의 경우 코드 그 자체가 문서의 역할을 해야 함)
- 정말 합당한 이유가 있지 않는 한, 통합개발환경(IDE)의 자동 서식을 따른다. (비주얼 스튜디오의 “Ctrl + K + D” 기능)
- 본 코딩표준을 따라 잘 짜여진 기존의 코드에서 배운다.
참조문서
이 코딩 표준은 아래의 코딩 표준들에서 영감을 얻었음.
IDE 도우미
비주얼 스튜디오에 import할 수 있는 세팅은 여기서 다운받을 수 있습니다.
POCU 아카데미에 비적용 사항
- 있을 경우 추후 추가 계획
I. 메인 코딩 표준
-
클래스와 구조체의 이름은 파스칼 표기법을 따른다.
class PlayerManager; struct PlayerData; -
지역 변수 그리고 함수의 매개 변수의 이름은 카멜 표기법을 따른다.
public void SomeMethod(int someParameter) { int someNumber; int id; } -
메서드 이름은 기본적으로 동사(명령형)+명사(목적어)의 형태로 짓는다.
public uint GetAge() { // 함수 구현부... } -
단, 단순히 부울(boolean) 상태를 반환하는 메서드의 동사 부분은 최대한
Is,Can,Has,Should를 사용하되 그러는 것이 부자연스러울 경우에는 상태를 나타내는 다른 3인칭 단수형 동사를 사용한다.public bool IsAlive(Person person); public bool HasChild(Person person); public bool CanAccept(Person person); public bool ShouldDelete(Person person); public bool Exists(Person person); -
아래에 제시된 예를 제외하곤 모든 메서드의 이름은 파스칼 표기법을 따른다.
public uint GetAge() { // 함수 구현부... } -
public 메서드가 아닌 경우 카멜 표기법을 따른다. Visual Studio를 사용 시에는 별도의 스타일 규칙을 추가해야 할 수도 있음. (자세한 설명)
private uint getAge() { // 함수 구현부... } -
상수의 이름은 모두 대문자로 하되 밑줄로 각 단어를 분리한다.
const int SOME_CONSTANT = 1; -
상수로 사용하는 개체형 변수에는
static readonly를 사용한다.public static readonly MyConstClass MY_CONST_OBJECT = new MyConstClass(); -
상수로 사용하는
static readonly변수는 모두 대문자로 하되 밑줄로 각 단어를 분리한다. -
초기화 후 값이 변하지 않는 변수는
readonly로 선언한다.public class Account { private readonly string mPassword; public Account(string password) { mPassword = password; } } -
네임스페이스의 이름은 파스칼 표기법을 따른다.
namespace System.Graphics -
부울(boolean) 변수는 앞에
b를 붙인다.bool bFired; // 지역변수 private bool mbFired; // private 멤버변수 -
부울 프로퍼티는 앞에
Is,Has,Can,Should중에 하나를 붙인다.public bool IsFired { get; private set; } public bool HasChild { get; private set; } public bool CanModal { get; private set; } public bool ShouldRedirect { get; private set; } -
인터페이스를 선언할 때는 앞에
I를 붙인다.interface ISomeInterface; -
열거형을 선언할 때는 앞에
E를 붙인다public enum EDirection { North, South } -
구조체를 선언할 때는 앞에
S를 붙인다. 단,readonly struct일 때는 그렇지 아니한다public struct SUserID; -
private멤버 변수명은 앞에m을 붙이고 파스칼 표기법을 따른다public class Employee { public int DepartmentID { get; set; } private int mAge; } -
값을 반환하는 함수의 이름은 무엇을 반환하는지 알 수 있게 짓는다.
public uint GetAge(); -
단순히 반복문에 사용되는 변수가 아닌 경우엔
i,e같은 변수명 대신index,employee처럼 변수에 저장되는 데이터를 한 눈에 알아볼 수 있는 변수명을 사용한다. -
뒤에 추가적인 단어가 오지 않는 경우 줄임말은 모두 대문자로 표기한다.
public int OrderID { get; private set; } public int HttpCode { get; private set; } -
getter와 setter 대신 프로퍼티를 사용한다.
틀린 방식:
public class Employee { private string mName; public string GetName(); public string SetName(string name); }올바른 방식:
public class Employee { public string Name { get; set; } } -
지역 변수를 선언할 때는 그 지역 변수를 사용하는 코드와 동일한 줄에 선언하는 것을 원칙으로 한다.
-
double이 반드시 필요한 경우가 아닌 이상 부동 소수점 값에f를 붙여준다float f = 0.5F; -
switch문에 언제나default:케이스를 넣는다.switch (number) { case 0: ... break; default: break; } -
switch문에서default:케이스가 절대 실행될 일이 없는 경우,default:안에 `Debug.Fail()을 추가한다.switch (type) { case 1: ... break; default: Debug.Fail("unknown type"); break; } -
코드를 작성하면서 세운 모든 가정에
Debug.Assert()를 넣는다. -
재귀 함수는 이름 뒤에
Recursive를 붙인다.public void FibonacciRecursive(); -
클래스 안에서 멤버 변수와 메서드의 등장 순서는 다음을 따른다.
- 멤버 변수
- 프로퍼티 (단, 프로퍼티와 대응하는 private 멤버변수는 프로퍼티 바로 위에 적음)
- 생성자
- 메서드 (public -> private 순서로)
-
클래스 안에서 연관 있는 메서드끼리 그룹을 짓는다. 멤버 변수도 마찬가지이다.
-
매개변수 자료형이 범용적인 경우, 함수 오버로딩을 피한다.
올바른 방식:
public Anim GetAnimByIndex(int index); public Anim GetAnimByName(string name);틀린 방식:
public Anim GetAnim(int index); public Anim GetAnim(string name); -
클래스는 각각 독립된 소스 파일에 있어야 한다. 단, 작은 클래스 몇 개를 한 파일 안에 같이 넣어두는 것이 상식적일 경우 예외를 허용한다.
-
파일 이름은 대소문자까지 포함해서 반드시 클래스 이름과 일치해야 한다.
public class PlayerAnimation { }PlayerAnimation.cs -
여러 파일이 하나의 클래스를 이룰 때(즉, partial 클래스), 파일 이름은 클래스 이름으로 시작하고, 그 뒤에 마침표와 세부 항목 이름을 붙인다.
public partial class Human;Human.Head.cs Human.Body.cs Human.Arm.cs -
특정 조건이 반드시 충족되어야 한다고 가정(assertion)하고 짠 코드 모든 곳에
assert를 사용한다.assert는 복구 불가능한 조건이다.(예: 대부분의 함수는 다음과 같은assert를 가질 수도…Debug.Assert(매개변수의 null 값 검사) ) -
비트 플래그 열거형은 이름 뒤에
Flags를 붙인다.[Flags] public enum EVisibilityFlags { None = 0, Character = 1 << 0, Terrain = 1 << 1, Building = 1 << 2, } -
디폴트 매개 변수 대신 함수 오버로딩을 선호한다.
-
디폴트 매개 변수를 사용하는 경우,
null이나false,0같이 비트 패턴이 0인 값을 사용한다. -
변수 가리기(variable shadowing)는 허용되지 않는다. 외부 변수가 동일한 이름을 사용중이라면 내부 변수에는 다른 이름을 사용한다.
public class SomeClass { public int Count { get; set; } public void Func(int count) { for (int count = 0; count != 10; ++count) { // count를 사용 } } } -
언제나
System.Collections에 들어있는 컨테이너 대신에System.Collections.Generic에 들어있는 컨테이너를 사용한다. 순수 배열을 사용하는 것도 괜찮다. -
var키워드를 사용하지 않으려 노력한다. 단, 대입문의 우항에서 데이터형이 명확하게 드러나는 경우, 또는 데이터형이 중요하지 않은 경우에는 예외를 허용한다.IEnumerable에var를 사용하거나 우항의new키워드를 통해 어떤 개체가 생성되는지 알 수 있는 등이 허용되는 경우의 좋은 예이다.var text = "string obviously"; var age = 28; var employee = new Employee(); string accountNumber = GetAccountNumber(); -
싱글턴 패턴 대신에 정적(
static) 클래스를 사용한다. -
async void대신에async Task를 사용한다.async void가 허용되는 유일한 곳은 이벤트 핸들러이다. -
async메서드명에-Async접미사를 붙이지 않는다. -
외부로부터 들어오는 데이터의 유효성은 외부/내부 경계가 바뀌는 곳에서 검증(validate)하고 문제가 있을 경우 내부 함수로 전달하기 전에 반환해 버린다. 이는 경계를 넘어 내부로 들어온 모든 데이터는 유효하다고 가정한다는 뜻이다.
-
따라서 내부 함수에서 예외(익셉션)를 던지지 않으려 노력한다. 예외는 경계에서만 처리하는 것을 원칙으로 한다.
-
위 규칙의 예외:
enum형을switch문에서 처리할 때 실수로 처리 안 한enum값을 찾기 위해default:케이스에서 예외를 던지는 것은 허용.switch (accountType) { case AccountType.Personal: return something; case AccountType.Business: return somethingElse; default: throw new NotImplementedException($"unhandled switch case: {accountType}"); } -
함수의 매개변수로
null을 허용하지 않는 것을 추구한다. 특히public함수일 경우 더욱 그러하다. -
null값을 허용하는 매개변수를 사용할 경우 변수명 뒤에OrNull를 붙인다public Anim GetAnim(string nameOrNull) { } -
함수에서
null을 반환하지 않는 것을 추구한다. 특히public함수일 경우 더욱 그러하다. 그러나 때로는 예외를 던지는 것을 방지하기 위해 그래야 할 경우도 있다. -
함수에서
null을 반환할 때는 함수 이름 뒤에OrNull을 붙인다.public string GetNameOrNull(); -
인라인 람다는 한 줄짜리 짧은 코드만 담을 수 있다. -
개체 초기자(object initializer)를 사용하지 않으려고 노력한다.
단,required한정자(C# 11.0)와 초기화 전용 setter(C# 9.0)와 같이 사용할 때는 괜찮다. -
함수에 전달하는
out매개변수는 별도의 라인에 선언한다. 즉, 인자 목록 안에서 선언하지 않는다. -
null 병합 연산자(C# 7.0)의 사용을 금한다.
-
using선언(C# 8.0)의 사용을 금한다. 대신using문을 사용한다. -
new키워드 뒤에 반드시 명시적으로 자료형을 적어준다. (즉, C# 9.0의new()사용 금지) -
프로퍼티에private init(C# 9.0)을 최대한 사용한다. -
파일 범위 namespace 선언(C# 10.0)을 사용한다 -
범용적인 자료형을 강타입(strong type)으로 만들 때는readonly record struct(C# 10.0)를 사용한다
II. 소스 코드 포맷팅
-
탭(tab)은 비주얼 스튜디오 기본값을 사용하며, 비주얼 스튜디오를 사용하지 않을 시 띄어쓰기 4칸을 탭으로 사용한다.
-
중괄호(
{)를 열 때는 언제나 새로운 줄에 연다. -
중괄호 안(
{ })에 코드가 한 줄만 있더라도 반드시 중괄호를 사용한다.if (bSomething) { return; } -
한 줄에 변수 하나만 선언한다.
틀린 방식:
int counter = 0, index = 0;올바른 방식:
int counter = 0; int index = 0;
TOP 1% 프로그래머 테크트리 | MIT급 컴공인강 | 코딩 독학순서
야근 없이 오직 실력으로 대우받는 프로그래머가 되고 싶다고요? 최저시급도 안 되는 수업료를 내고 최고연봉을 받는 프로그래머가 되세요!