매직 문자열 / 숫자 사용법 [닫힘]


31

이것은 다소 논란의 여지가있는 주제이며 프로그래머가있는만큼 많은 의견이 있다고 생각합니다. 그러나 그것을 위해, 나는 사업 (또는 직장)에서 일반적인 관행이 무엇인지 알고 싶습니다.

우리 직장에는 엄격한 코딩 지침이 있습니다. 그 중 한 섹션은 마법의 문자열 / 숫자 전용입니다. (C #의 경우)

기호 상수를 정의하기 위해 코드에 리터럴 값 (숫자 또는 문자열)을 사용하지 마십시오. 상수를 정의하려면 다음 패턴을 사용하십시오.

public class Whatever  
{  
   public static readonly Color PapayaWhip = new Color(0xFFEFD5);  
   public const int MaxNumberOfWheels = 18;  
}

예외는 0, 1 및 null 값을 거의 항상 안전하게 사용할 수 있습니다. 종종 값 2와 -1도 OK입니다. 로깅 또는 추적 용 문자열은이 규칙에서 제외됩니다. 리터럴은 문맥에서 의미가 명확 할 때 허용되며 향후 변경 될 수 없습니다.

mean = (a + b) / 2; // okay  
WaitMilliseconds(waitTimeInSeconds * 1000); // clear enough

이상적인 상황은 다음과 같은 경우 코드의 가독성 / 유지 보수성에 영향을 미치는 공식 연구 논문입니다.

  • 마법의 숫자 / 문자열이 여기 저기 있습니다
  • 매직 문자열 / 숫자는 합리적으로 (또는 다른 범위의 범위에서) 일정한 선언으로 대체됩니다. "합리적으로"사용하여 나에게 소리 지르지 마십시오. 모든 사람들이 "합리적으로"가 무엇인지 다른 생각을 가지고 있음을 알고 있습니다
  • 매직 스트링 / 넘버는 초과되거나 필요하지 않은 곳에 교체됩니다 (아래 예 참조).

나는 내 동료 중 한 사람과 논쟁 할 때 과학적 기반의 논쟁을하기 위해이 작업을 수행하고 싶습니다.

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

또 다른 예는 다음과 같습니다 (이것은 JavaScript입니다).

var someNumericDisplay = new NumericDisplay("#Div_ID_Here");

해당 ID가 한 곳에서만 사용되는 경우 Javascript 파일 위에 DOM ID를 사용합니까?

다음 항목을 읽었습니다.
StackExchange
StackOverflow
바이트 IT 커뮤니티
더 많은 기사가 있으며 이러한 패턴을 읽은 후 더 많은 패턴이 나타납니다.

그래서 내 질문은 코드에서 마술 문자열과 숫자를 사용해야합니까? 가능한 경우 참조로 뒷받침되는 전문가 답변을 찾고 있습니다.


2
매직 변수는 내용에 반영되지 않는 의미를 보유하는 변수입니다. 정수 값 '10'은 숫자 10의 의미를 반영하므로 상수로 만들 필요가 없습니다. 공간과 세미콜론도 마찬가지입니다. 반면에 '%% ?? %%'값이 있고 이것이 사용자 지정 구분 기호 인 경우 해당 내용이 구분 기호라는 사실을 반영하지 않기 때문에 HAS를 상수로 배치해야합니다.
Jeroen Vannevel

23
NumberTen = 10숫자 10이 재정의되지 않으므로 무의미합니다. MaxRetryCount = 10최대 재시도 횟수를 변경하려는 점이 있습니다. private const char SemiColon = ';'; 우둔한. private const char LineTerminator = ';'; 똑똑한.
Mike

1
실제 질문은 명확하지 않습니다.
Tulains Córdova

답변:


89

... 내 동료 중 한 명과 논쟁 할 때 누가 다음과 같은 상수를 선언 할 것입니다.

private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

동료와 함께해야 할 주장은 문자 공간의 이름을 지정하는 Space것이 아니라 상수에 대한 그의 이름을 잘못 선택하는 것입니다.

코드의 작업은 세미콜론 ( a;b;c)으로 구분되고 공백 ( a;b;c d;e;f) 으로 구분 된 필드를 포함하는 레코드 스트림을 구문 분석하는 것 입니다. 누가 당신의 스펙을 작성한 사람이 지금부터 한 달 후에 전화를해서 "우리가 착각 a|b|c d|e|f했다면, 레코드의 필드는 파이프 기호 ( ) 로 분리됩니다"라고 말하면 어떻게해야합니까?

동료가 선호하는 이름으로 구성표 아래에서 리터럴 ( SemiColon = '|') 의 값을 변경하고 SemiColon더 이상 세미콜론이 아닌 무언가에 계속 사용되는 코드를 사용해야 합니다. 그것은 코드 리뷰에서 부정적인 의견으로 이어질 것 입니다. 그를 경감하기 위해, 당신은에 리터럴의 이름을 바꿀 수 PipeSymbol및 통과 및 발생할 때마다 변경 SemiColon에를 PipeSymbol. 이 속도에서 처음에는 리터럴 세미콜론 ( ';')을 사용했을 수도 있습니다. 각 사용을 개별적으로 평가해야하고 동일한 수의 변경을 수행해야하기 때문입니다.

상수에 대한 식별자의 설명 할 필요가 값이 무엇을 하지 , 값이없는 것 입니다 , 당신의 동료가 잡초에 좌회전을했다의 것을. 위에서 설명한 필드 분할 응용 프로그램에서 세미콜론의 목적은 필드 구분 기호이며 상수는 그에 따라 이름을 지정해야합니다.

private const char FieldSeparator = ';';    // Will become '|' a month from now
private const char RecordSeparator = ' ';
private const int MaxFieldsPerRecord = 10;

이렇게하면 필드 구분 기호가 변경 될 때 상수 선언이라는 정확히 한 줄의 코드를 변경합니다. 변경 사항을보고있는 사람은 한 줄만보고 필드 구분 기호가 세미콜론에서 파이프 기호로 변경되었음을 즉시 이해할 수 있습니다. 상수를 사용했기 때문에 변경할 필요가없는 나머지 코드는 동일하게 유지되며 독자는 코드를 통해 다른 작업을 수행 할 필요가 없습니다.


전적으로 동의합니다. 수십 년 전에 저는 8 개의 일반 레지스터를 사용하여 메시지가 세그먼트로 전송되는 프로젝트를 진행했습니다. 누군가 #define one 1 #define two 2 등 을 선언했습니다 (또는 그에 상응하는 언어 인 영국 우체국 산호에 해당하는 것이 무엇이든). 말씀은 미래에 길이 필드가 너무 바이트가 아닌 세그먼트의 수있을 것이라고 높은 곳에서 온 분명히 코드가 변경되었습니다 #define one 8 #define two 16
Mawg

3
세미콜론 또는 PipeSymbol과 같은 이름이 바보처럼 보이지만 스크립트를 사용하여 서로 변경하는 것이 영향 ;을 받는 모든 항목을 변경하는 것보다 훨씬 쉽습니다 |.
Brandin

주어진 문자열 리터럴이 파일에서 여러 번 사용되지만 값 이외의 의미는없는 경우는 어떻습니까? 예를 들어, 20 가지 시나리오에서 맵에서 특정 키를받을 수 있는지 테스트하는 경우 상수를 다음과 같이 정의해야합니까? public static final String MY_KEY_NAME = "MyKeyName"
Jordan McQueen

1
@JordanMcQueen 각 문자가 정확히 한 번만 사용되고 다른 곳에서는 필요하지 않은 경우 베어 리터럴을 사용하는 경우가 있습니다. 다른 파일 형식을 처리하는 각 시나리오의 존재 코드와 같은 그것의 무언가가, 각 형식 (예를 들어, 자신의 상수를 정의해야하는 경우 CSV_RECORD_SEPARATOR, TSV_RECORD_SEPARATOR등).
Blrfl

8

세미콜론 은 이미 상수 이기 때문에 세미콜론을 상수로 정의하는 것은 중복 됩니다 . 결코 변하지 않을 것입니다.

언젠가 누군가가 "용어의 변경, + 는 새로운 세미콜론 "이라고 발표하는 것과 같지 않으며 , 동료는 상수를 업데이트하기 위해 행복하게 돌진 할 것입니다 (그들은 나를 비웃었습니다.

일관성 문제도 있습니다. 나는 그의 NumberTen상수가 모든 사람들에 의해 사용되지 않을 것임을 보장합니다 (대부분의 코더는 마음에 들지 않습니다). 어쨌든 기대했던 어떤 목적에도 도움이되지 않습니다. 묵시가오고 "ten"이 전체적으로 9로 재조정 될 때 상수를 업데이트하면 10코드 에 리터럴이 남게되므로 트릭을 수행하지 않으므로 이제 시스템이 범위 내에서도 완전히 예측할 수 없게됩니다. "10"은 "9"를 의미하는 혁신적인 가정.

모든 설정을 const로 저장하는 것도 두 번째 생각입니다. 이것을 가볍게하지 말아야합니다.

우리는 지금까지 이러한 유형의 사용에 대해 어떤 예를 모았습니까? 라인 터미네이터 ... 최대 재시도 횟수 ... 최대 휠 수 ... 절대 바뀌지 않을 것입니다.

기본 설정을 변경하려면 응용 프로그램을 다시 컴파일해야하고 경우에 따라 종속성도 계산해야합니다 (숫자 const 값이 컴파일 중에 하드 코딩 될 수 있음).

테스트 및 조롱 측면도 있습니다. 연결 문자열을 const로 정의했지만 단위 테스트에서 데이터베이스 액세스를 모방 할 수 없습니다 (가짜 연결 설정).


4
"그것은 결코 변하지 않을 것입니다." 나는 아포스트로피에 대해 (ASCII 값 39에 영원히 묶여) 생각했습니다. 일부 오래된 앱은 아포스트로피를 말리는 데 사용되었습니다. 그러나 현재 현대 응용 프로그램은 해당 ASCII 값을 이전 응용 프로그램과 호환되는 직선 아포스트로피로 취급하고 대신 사람들 은 말린 마크에 다른 글리프를 표시하는 데 호환되는 응용 프로그램에 종종 (왼쪽 작은 따옴표, 유니 코드 8217 )을 사용합니다. 유럽이 미국인들이 마침표를 소수점으로 사용하는 방식으로 쉼표를 사용하기 때문에, 나는 "... ....
TOOGAM

@TOOGAM 아니라, 귀하의 예를 들어 정당화는 필요 DecimalPoint상수 -하지만 CommaPeriod상수. 전자는 기능 , 역할 또는 가치의 목적을 나타냅니다 . "세미콜론"또는 "쉼표"는 해당 범주에 속하지 않습니다.
Konrad Morawski

Decimal Point 예제에서도 마찬가지입니다. 그러나 아포스트로피 예제는 쉼표 (또는 세미콜론)와 유사한 (또는 동일한) 범주 인 것 같습니다.
TOOGAM

@KonradMorawski Semicolon은 문자열을 나누거나 줄을 끝내는 것과 같은 많은 목적으로 사용될 수 있습니다. 콘 스턴스 이름을 지정하는 데 사용해야하는 것은 값이 아니라 그 의미입니다. 미래의 변화, 즉 내일 20 개의 레코드가 처리되도록 허용하므로 NumberTen 이라는 이름의 콘 스턴스 가 컨텍스트를 벗어나지maxRecord 는 여전히 양호합니다.
MaxZoom

5
private const char SemiColon = ';';
private const char Space = ' ';
private const int NumberTen = 10;

그래서 당신의 동료는 매일 WTF 엔트리를 목표로하고 있습니다. 이러한 정의는 어리 석고 중복됩니다. 그러나 다른 사람들이 지적했듯이 다음 정의는 어리 석거나 중복 되지 않습니다 .

private const char StatementTerminator = ';';
private const char Delimiter = ' ';
private const int  BalanceInquiryCode = 10;

"매직"숫자와 문자열은 문자 그대로의 값을 넘어서는 의미를 갖는 상수입니다. 상수 10가 "10 가지"이상의 의미를 갖는 경우 (예 : 특정 연산 또는 오류 조건에 대한 코드), "매직"이되고 추상적 인 의미를 설명하는 기호 상수로 대체되어야합니다.

의도를 명확하게 설명하는 것 외에도 기호 상수는 리터럴의 철자를 잘못 입력 할 때 두통을 줄여줍니다. 한 줄의 코드에서 "CVS"에서 "CSV"로의 간단한 전치가 단위 테스트와 QA를 거쳐 생산으로 전환되어 특정 작업이 실패했습니다. 예, 분명히 단위 및 QA 테스트는 불완전한 것이며 자체 문제입니다. 그러나 기호 상수를 사용하면 그러한 가슴 앓이를 피할 수 있었을 것입니다.


3

그것에 대해 논쟁의 여지가 없어야합니다. 요점은 마법의 숫자를 사용하거나 사용하지 않는 것이 아니라 읽을 수있는 코드를 갖는 것입니다.
의 차이를 고려 if(request.StatusCode == 1)하고 if(request.HasSucceeded). 이 경우 후자가 훨씬 더 읽기 쉽다고 주장하지만 그렇다고 코드를 가질 수는 없습니다 int MaxNumberOfWheels = 18.

추신 : 이것이 내가 코딩 지침을 절대적으로 싫어하는 이유입니다. 개발자는 이와 같은 판단을 할 수있을 정도로 성숙해야합니다. 그들은 그것을 신이 만든 텍스트에 남겨 두지 말아야한다.


13
운전자는 도로의 어느 쪽을 운전하는지 판단 할 수있을 정도로 충분히 성숙해야합니다.)
Konrad Morawski

2
판단 요청의 결과는 성숙한 개발자들 사이에서도 다를 수 있으므로 임의의 코딩 지침조차도 일관성을 통해 가독성을 향상시킵니다. 상수 NumberTen을 만드는 것이 의미가 없다는 사실과 관련이 없습니다.
Mike Partridge

1
나는 그들이 형식적, 각인 등이어야한다고 주장하지 않을 것이며, 비공식적이지만 동의해야하며, 이는 이미 개인의 성숙도 판단을 사용하는 것 이상입니다. 그러나 당신은 지금 귀하의 의견을 삭제했습니다 Stefan :)
Konrad Morawski

1
@StefanBilliet-전혀 아닙니다. 내 요점은 일관성을 통해 가독성이 향상된다는 것입니다. 여기서 문제는 코딩 가이드 라인 자체가 아니라 오해를 통해 극단적 인 가이드 라인입니다.
Mike Partridge

@MikePartridge 어쩌면 내가 정교하게 만들어야했을 것입니다. 아마의 :-) 내가 본 코딩 가이드 라인보다 누군가 어딘가에 그 소프트웨어가 아니라 당신과 콘라드 같은 계약보다, 작성해야한다고 생각 방법에 대한 일반적인 룰북의 추세에있는 생각을
스테판 Billiet
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.