C# 코드를 단순화하는 14가지 방법 - Tim Corey의 비디오에서 온 팁
Tim Corey는 그의 포괄적인 비디오 " C# 코드를 간소화하는 14가지 방법 "에서 코드 가독성을 향상시키고, 코드의 복잡성을 줄이며, 코드베이스의 유지 관리성을 높이는 실용적인 C# 모범 사례를 살펴봅니다. 팀은 한 줄짜리 명언이나 난해한 트릭에 집착하기보다는 좋은 코딩 관행, 즉 다른 개발자들이 따라할 수 있는 깔끔하고 이해하기 쉬운 코드를 작성하는 방법에 집중합니다.
그는 Visual Studio의 실제 예제를 통해 각 팁을 설명하며, 명명 규칙, 오류 처리, 심지어 코드를 손상시키지 않고 리팩토링하는 방법까지 다룹니다. 이것은 단순히 이론이 아니라, 실습을 통해 코드가 더 나아진다는 것을 의미합니다.
이 글에서는 그가 보여준 14가지 방법을 하나씩 살펴보겠습니다.
1. 더 깔끔한 코드를 위해 정적 변수를 사용하세요
팀은 정적 액세스가 반복적인 호출을 어떻게 단순화할 수 있는지 보여주는 것으로 시작합니다. 다음과 같이 선언함으로써:
using static System.Console;using static System.Console;이제 모든 정적 멤버 앞에 Console을 붙일 필요가 없습니다.
이는 단순히 단어를 제거하는 것 이상으로, 정적 접근 방식을 명확하게 하는 것입니다. Tim은 Console이나 Math처럼 자주 사용되는 클래스에 정의된 정적 멤버를 호출할 때 이러한 단축 표현이 코드 가독성을 향상시킨다고 지적합니다.
하지만 좋은 코딩 습관의 일환으로 그는 개발자들이 충돌을 피해야 한다고 경고합니다. 즉, 서로 다른 두 클래스가 정적 멤버에 대해 동일한 이름을 가질 수 있다는 것입니다. 예상치 못한 행동이 발생할 가능성을 인지하는 것이 중요합니다.
2. 리스트 초기화
이제 C#에서 리스트를 보다 직접적으로 초기화할 수 있습니다.
List<string> names = ["Tim", "Sue", "Bilbo"];List<string> names = ["Tim", "Sue", "Bilbo"];팀은 이것이 모든 것을 하나의 명령문에 억지로 집어넣는 것이 아니라, 코드를 더 읽기 쉽게 만들고 불필요한 표현을 줄여 성능을 최적화하는 것이라고 설명합니다.
"새로운 문자열 목록"과 같은 정형화된 문구를 분석하는 대신, 독자는 컬렉션에 있는 설명적인 이름, 즉 핵심적인 내용만 정확히 볼 수 있습니다. 팀은 이러한 방식이 배열이나 딕셔너리에도 적용 가능하며, 명확성을 우선시하는 코딩 관례와 일치한다고 언급했습니다.
3. 대상 유형 새 항목
또 다른 시간 절약 방법: 대상 유형이 지정된 새 항목. 대신:
List<int> numbers = new List<int>();List<int> numbers = new List<int>();다음과 같이 쓸 수 있습니다:
List<int> numbers = new();List<int> numbers = new();Tim은 클래스 이름을 반복하는 것은 불필요하다고 강조합니다. 이미 왼쪽에 나와 있기 때문입니다. 이는 중복을 제거하고 코드베이스를 더 쉽게 읽을 수 있도록 하는 좋은 코딩 관행을 따르는 것입니다.
4. 변수 및 익명 타입
팀은 코딩 실무 분야에서 논쟁을 불러일으키는 기능인 var를 다룹니다. 일부 사람들은 변수 이름과 유형을 숨긴다는 이유로 이를 싫어하지만, 팀은 익명 타입의 존재가 진정한 강점이라고 설명합니다.
Tim은 Dapper를 통해 SQL과 같은 데이터 소스를 다룰 때 var를 사용하여 객체를 즉시 생성하는 방법을 보여줍니다.
var parameters = new { FirstName = "Tim", LastName = "Corey" };var parameters = new { FirstName = "Tim", LastName = "Corey" };이는 쿼리 작성이나 일회성 객체 생성에 적합합니다. 매개변수만을 위한 기본 클래스를 만들 필요가 없습니다. Tim이 말했듯이, 이렇게 하면 불필요한 타입으로 코드베이스가 오염되는 것을 방지하면서도 문제가 발생할 경우 의미 있는 오류 메시지를 제공할 수 있습니다.
5. 파일 범위 네임스페이스
Tim은 파일 범위 네임스페이스로 넘어가면서 그 방법을 보여줍니다.
namespace ProjectName
{
// indented code
}namespace ProjectName
{
// indented code
}이렇게 됩니다:
namespace ProjectName;namespace ProjectName;이 작은 변경 사항은 불필요한 들여쓰기를 없애고 공개 멤버에 대해 파스칼식 명명 규칙과 같은 C# 명명 규칙을 준수합니다. 팀은 대부분의 파일에 하나의 네임스페이스만 포함되어 있기 때문에 코드 가독성이 향상되고 논리적 섹션이 일관되게 유지된다고 설명합니다.
6. 한 줄 데이터 구조에 대한 기록
레코드를 사용하면 단 하나의 명령으로 데이터 객체를 정의할 수 있습니다.
public record EmployeeRecord(int Id, string Name);public record EmployeeRecord(int Id, string Name);Tim은 이 방법이 최소한의 노력으로 속성, 불변성 및 ToString()을 포함한 완전한 유형을 생성한다고 언급합니다. 그는 파생 클래스 시나리오에서도 여전히 클래스가 필요하지만, 객체가 읽기 전용일 경우 레코드는 단일 책임 원칙에 따라 하나의 기능을 제대로 수행한다고 분명히 밝혔습니다.
7. 패턴 매칭
Tim은 패턴 매칭을 사용하여 예외를 처리하고 안전하게 비교를 수행하는 방법을 보여줍니다. 장황한 타입 검사 코드를 작성하는 대신, 이들을 결합할 수 있습니다.
if (emp is EmployeeRecord e)
{
e.Id = 1;
}if (emp is EmployeeRecord e)
{
e.Id = 1;
}이 한 줄짜리 코드는 확인과 캐스팅을 담당합니다. 팀은 이것이 좋은 코딩 관행과 일치한다고 말합니다. 즉, x나 y처럼 한 글자로 된 변수 이름을 피하고 e처럼 설명적인 이름을 사용하는 것입니다. 명확한 메서드 이름과 변수 이름은 다른 개발자들이 코드를 유지 관리하기 쉽게 해줍니다.
8. 문자열 보간
읽기 쉬운 문자열을 만들기 위해 Tim은 문자열 보간법을 시연합니다.
$"The employee with ID {e.Id} is {e.Name}"$"The employee with ID {e.Id} is {e.Name}"그는 이로 인해 의미 있는 오류 메시지를 작성하고 주석을 달기가 더 쉬워진다고 지적합니다. 복잡하게 얽힌 문자열 연결 대신, 말 그대로 영어처럼 읽기 쉬운 코드를 작성할 수 있어 코드 품질이 향상되고 출력 결과를 확인하는 향후 단위 테스트가 간소화됩니다.
9. 안전한 리팩토링을 위한 nameof() 함수
Tim은 코드 리팩토링 시 nameof()가 어떻게 여러분을 보호하는지 보여줍니다. 문자열에 하드코딩된 변수 이름은 이름을 변경할 경우 예기치 않은 동작을 초래할 수 있습니다. 하지만 다음과 같이 글을 쓰면:
nameof(emp)nameof(emp)컴파일러는 사용될 때마다 자동으로 업데이트됩니다. 이는 깔끔한 코드를 작성하고 재구성함으로써 코드베이스를 건강하게 유지하는 데 도움이 되는 모범 사례 중 하나입니다.
10. 여러 반환 값을 위한 튜플
Tim은 단순히 두 개의 값만 반환하는 기본 클래스를 만드는 대신 튜플을 사용합니다.
(string FirstName, string LastName) SplitName(string fullName)(string FirstName, string LastName) SplitName(string fullName)이렇게 하면 불필요한 외부 의존성을 방지하고 단일 책임 원칙을 준수할 수 있습니다. 이 메서드는 단순히 이름을 분할할 뿐입니다. 팀이 말했듯이, 과도한 설계를 피하면 연습을 통해 코드가 더 나아집니다.
11. 해체
Tim은 튜플을 기반으로 결과를 로컬 변수로 분해하는 방법을 보여줍니다.
var (firstName, lastName) = SplitName("Tim Corey");var (firstName, lastName) = SplitName("Tim Corey");이렇게 하면 변수 이름이 설명적으로 유지되고 나중에 모호한 튜플 구문을 사용하는 것을 방지할 수 있습니다. Tim은 사용되지 않는 값을 버리는 것(밑줄(_) 사용)에 대해서도 언급하는데, 이는 한 글자로 된 변수 이름도 설명 없이 남겨두지 않겠다는 의도를 나타냅니다.
12. 불필요한 값 제거
튜플의 모든 부분이 필요하지 않다면 Tim은 디스카드 기능을 사용할 것을 권장합니다.
var (firstName, _) = SplitName("Tim Corey");var (firstName, _) = SplitName("Tim Corey");이는 다른 개발자들에게 당신이 의도적으로 특정 값을 무시하고 있음을 보여줍니다. 모든 출력값이 중요하지 않은 프레임워크 테스트나 단위 테스트에 유용합니다.
13. 블록 없이 문장 사용하기
팀은 자원 관리 및 오류 처리 업무로 이동합니다. 이전에는 다음과 같이 작성했습니다.
using (var connection = new SqlConnection(connString))
{
// work
}using (var connection = new SqlConnection(connString))
{
// work
}이제 다음을 사용할 수 있습니다.
using var connection = new SqlConnection(connString);using var connection = new SqlConnection(connString);이는 SOLID 원칙, 특히 단일 책임 원칙과 의존성 역전 원칙에 부합합니다. Tim은 이 구문이 데이터베이스와 같은 외부 종속성에 효과적이며, 대부분의 예외 처리가 더 깔끔해지고 연결이 항상 닫히므로 연결이 해제되지 않을 때 발생하는 성능 문제나 SQL 인젝션 시나리오를 방지할 수 있다고 언급합니다.
14. 변수 선언을 인라인으로 내보냅니다.
마지막으로 Tim은 구문 분석과 같은 작업을 위해 변수 선언을 인라인으로 내보내는 방법에 대해 설명합니다.
if (int.TryParse(numberText, out int numberValue))if (int.TryParse(numberText, out int numberValue))여기서는 지역 변수를 같은 줄에 생성합니다. 이렇게 하면 코딩 규칙을 엄격하게 유지하고 메서드 이름을 명확하게 지정할 수 있습니다. 코드를 적절하게 그룹화하면 예상치 못한 동작을 줄이고 향후 리팩토링 작업을 더욱 안전하게 수행할 수 있습니다.
마무리
팀은 영상 말미에 시청자들에게 이러한 간소화는 난해한 한 줄짜리 코드를 작성하는 것이 아니라 좋은 코딩 습관을 들이는 것이라는 점을 다시 한번 강조합니다. 정적 변수, 레코드, 패턴 매칭, 튜플, 디스카드 등의 기능을 사용하면 깔끔하고 현대적인 C# 코드를 작성할 수 있습니다.
그는 개발자들이 이러한 기능을 도입할 때 명명 규칙, 오류 처리 및 의미 있는 이름에 대해 생각하도록 권장합니다. 팀은 "코드는 사람이 읽을 수 있도록 만들어진 것"이라고 말합니다. 이해하기 쉬운 코드를 작성하면 자신뿐 아니라 다른 개발자들의 삶도 더 나아집니다.
요약하자면, C# 모범 사례를 수용하고 단일 책임 원칙, 인터페이스 분리 원칙, 의존성 역전 원칙과 같은 SOLID 원칙을 준수하면 코드가 컴파일될 뿐만 아니라 성능이 향상되고 예상치 못한 동작이 줄어들며 팀원들이 즐겁게 코딩할 수 있게 됩니다.

