private static 함수

이런 게 팁이 될 수 있을지는 모르겠지만 문득 생각이 들어서 남깁니다.

Visual Studio가 코드를 최적화 할 수 있는 많은 부분들을 제시해준다는 것을 알고 계실 것입니다.

가령 기존의 C# 코드를 최신 문법의 C#코드로 제안해주는 것이죠.

  • foreach문을 linq로 바꿔주거나
  • .ToList()나 ToArray(), Concat() 같은 것을 [.. ] 이런식으로 Collection Expression으로 바꿔주거나
  • SubString() 같은 것을 [5,3] 이런식으로 Range-Operator를 제안해준다거나

기타 등등 아주 많습니다.

저도 코드를 작성한 기간이 늘어가면서 경력자들이 유지보수를 위해 나름대로의 쪼개기에 대한 경험과 기준이 생겨나고 있는데(그 기준이 일반적인 개발자의 기준이길 간절히 희망합니다.)

코드를 작성해서 함수에서 어떤 행위들이 묶어져서 동작한다면… 이전에는 개발 초기엔

// 창고에서 데이터를 가져와서 유효성 체크

이렇게 주석을 남겼습니다. 최근까지는

#region 창고에서 데이터를 가져와서 유효성 체크

#endregion

이렇게 바꿨구요.

하지만 region 역시 주석과 큰 차이점이 없으며 그냥 코드 접히는 기능말곤 없어서 private 메서드를 사용하기 시작했습니다.

기능을 요약한 문자열을 쭉 쓰는게 아니라 함수이름으로 명시하기에도 좋아서인데요.

그런데 private 메서드를 만들다보니 VS에서 class 안의 어떤 속성이나 필드를 참조하지 않는 기능이라면 독립된 기능이라는 걸 명시하기 위해서 static을 추가하는 것을 추천하더군요.

그래서 private 메서드 내부에서 class 의 field나 property를 참조하지 않고 오로지 parameter에만 의존하고 있다면 private static 메서드를 사용하는 것으로 했습니다.

개발자 입장에서는 굳이 안해줘도 되는 것이지만, VS와 .NET의 코드 최적화 기능을 최대한 받기 위해서는 추천해주는대로 개발하는 것이 좋다는 의견이기 때문입니다. var도 마찬가지겠지요.

코드 최적화란, 제가 알고 있기론 내가 눈으로 보고 있는 코드파일을 그대로 빌드하는 게 아니라 ms build 입장에서 진짜로 빌드가 들어가기 전에 코드를 빌드가 유용한 방향으로 자기 맘대로 바꿔버리는 것으로 쉽게 이해 가능합니다.

  • 코드 인라인 기능
  • 상속이 필요하지 않은 클래스에 sealed 적용하기
  • static property 로 문자열을 쓰기보다는 const로 적용하기

등등…더 많이 있을 것입니다.

사람 친화적인 코드보다는 그래도 기계 친화적으로 코드를 작성해서 ms build가 .NET을 더 잘 build 해주길 바라는 마음으로 오늘도 private static 메서드를 작성해 봅니다.

9개의 좋아요

인스턴스 상태값을 변경/참조하지 않는 메서드는 static 한정자로 변환하는게 여러모로 이득인 부분인 것 같습니다.

  • 개발자 입장에서는 단순히 단어 하나 더 적는 간단한 작업으로 성능적 이점을 가짐

  • 인스턴스의 상태값을 변경/참조하는 메서드인지 아닌지 즉각적으로 알 수 있음.
    (Functional programming 에서 말하는 Stateless 한 메서드 여부)

3개의 좋아요

static은 말씀하신 대로 인스턴스 멤버에 접근하지 않을 때 제안 되는데, 여기에는 세 가지 의미가 있습니다.

  1. 매개 변수에만 의존
  2. 상수에 접근
  3. 정적 변수에 접근

예를 들어, 인텔리센스는 아래 세 메서드 모두에 static 으로 한정하라는 제안을 하지만, AddOffset에만 static 을 붙이는 것을 고려하는 것이죠.

const int Threshold_ = 10;

int Add(int left, int right) => right + left; // 매개 변수에만 의존
int Offset(int number) = number - Threshold_; // 상수에 의존
bool IsFuture(DateTime date) => date > DateTime.Now; // 정적 변수에 의존.

이렇게 하는 이유는 C# 에서는 Lazy evaluation 과 비동기 호출이 많기 때문입니다.

순수성을 보장하지 않는 그룹(인스턴스 메서드와 전역 변수에 의존하는 메서드)은 위와 같은 호출에서 문제를 유발하는데, static 은 위와 같은 호출에서 안전함을 표시하는 마킹으로 사용하고 있습니다.

4개의 좋아요

음 제 코드에서는

제 경우 Offset에서 내부 필드를 참조하고 있으면 static을 제안하지 않습니다.

그래서 보니까 const를 예시로 들어주셔서 그런 듯 합니다.
const는 코드 최적화를 진행하면서 C언어의 define 처럼 상수값으로 코드를 치환한 뒤 빌드에 들어가기 때문에 변수로 취급되지 않을 것 같습니다. (이것은 아마도 제 생각)

그래서 아래와 같이 바꾸면 Offset과 Offset2에 대해서는 static으로 바꾸라는 제안을 하지 않습니다.

int Threshold_ = 10; // const 아님

int Add(int left, int right) => right + left; // 매개 변수에만 의존
int Offset(int number) => number - Threshold_; // 상수에 의존
int Offset2(int number)
{
    return number - Threshold_;
}
bool IsFuture(DateTime date) => date > DateTime.Now; // 정적 변수에 의존.

const로 선언하지 않은 경우에도 Lazy evaluation과 같은 선상에 놓고 문제를 볼 수 있을까요?

생각해보니 static 자체가 Lazy 한 만큼 => 로 expression 형태로 사용해도 Lazy 한 문제라고 불 수 있을 것 같습니다. 통찰 감사합니다!

4개의 좋아요

부가적으로 잘 구현된 static 메서드는 상태를 갖지 않기 때문에 Mock이 필요한 일부 시나리오를 제외하면 테스트하기에도 좋습니다.

4개의 좋아요

static 자체가 Lazy 하지는 않습니다.

본문에 언급한 "Lazy evaluation"은 선언과 실행이 분리되는 경우, 대표적으로 Linq 메서드와 Lazy<T>의 생성자에 전달될 때 안전한 것들만 static 으로 한정한다는 의미입니다.

2개의 좋아요

하긴 제가 static 의 여러 문법적 용도를 고려하지 않고 적어서 혼선이 있을 법한 표현이네요. 죄송합니다. 정정하겠습니다.

static object라면 그 자체 Lazy Loading 이라 Lazy가 맞지만 static Method라면 잘 모르겠습니다.

3개의 좋아요