매직 넘버는 무엇이며 왜 나쁜가요? [닫은]


514

매직 넘버는 무엇입니까?

왜 피해야합니까?

적절한 경우가 있습니까?


2
당신은 다른 사람들이 당신의 코드를보고있는 이유를 이해하지 못할 수도있는 매직 넘버를 피할 const myNum = 22; const number = myNum / 11;것입니다. 주민과 같은.
JuicY_Burrito

속성에 마법의 숫자를 사용하는 것은 피할 수 없으므로 이것이 적절하다고 생각합니다.
donatasj87

답변:


574

매직 넘버는 코드에서 숫자를 직접 사용하는 것입니다.

예를 들어, Java로 된 경우 :

public class Foo {
    public void setPassword(String password) {
         // don't do this
         if (password.length() > 7) {
              throw new InvalidArgumentException("password");
         }
    }
}

이것은 다음과 같이 리팩토링되어야합니다.

public class Foo {
    public static final int MAX_PASSWORD_SIZE = 7;

    public void setPassword(String password) {
         if (password.length() > MAX_PASSWORD_SIZE) {
              throw new InvalidArgumentException("password");
         }
    }
}

코드의 가독성을 향상시키고 유지 관리가 더 쉽습니다. GUI에서 암호 필드의 크기를 설정 한 경우를 상상해보십시오. 마법의 숫자를 사용하면 최대 크기가 변경 될 때마다 두 개의 코드 위치에서 변경해야합니다. 하나를 잊어 버리면 불일치가 발생합니다.

JDK에는이처럼 예 가득 Integer, CharacterMath클래스.

추신 : FindBugs 및 PMD와 같은 정적 분석 도구는 코드에서 마술 숫자의 사용을 감지하고 리팩토링을 제안합니다.


174
0과 1은이 규칙의 예외입니다.
Jonathan Parker

24
@Kirill : "백 퍼센트"의 정의가 변경 될 것으로 예상되면 예입니다. 더 좋은 방법은 변수를 나타내는 것부터 변수에 나타내는 것, 즉 public static final MAX_DOWNLOAD_PERCENTAGE = 100입니다. "100 %"는 매우 잘 정의되어 있기 때문에 의미가 없습니다. 반면에 암호의 길이는 최대 7 자일 수 있다는 사실은 전체적으로 정의되어 있지 않으며 실제로는 다르므로 변수의 후보입니다.
Michael Stum

40
@Jonathan Parker, 그들이 아닌 경우를 제외하고 ( TRUE/ FALSE)
Brendan Long

82
매직 넘버가 절대 변하지 않는다고해서 상수로 대체해서는 안된다는 의미는 아닙니다. 내 코드는 HzPerMHz 및 msecPerSecond와 같은 전역 상수로 가득합니다. 이것들은 결코 변하지 않을 것이지만, 그 의미를 더 명확하게하고 오타로부터 약간의 보호를 제공합니다.
Jeanne Pindar

43
@MarcusJ 더 이상 틀릴 수 없습니다. 이것은 많은 프로그래머들에 의한 의견의 문제가 아니라 어려운 경험의 문제입니다. 지난 40 년 동안 프로그래밍을 통해 상수를 정의하지 않은 이전 프로그래머를 저주했다는 것을 몇 번이나 말할 수 없으므로 코드 유지 관리 중에 이해해야하는 숫자의 직접적인 사용 만 발견했습니다. , 많은 코드 어딘가에 묻혔습니다. 그 상수를 정의하여 그 의미를 분명히했습니다. 다른 선임 프로그래머도 마찬가지로이 라인을 따라 여러 번의 공포 이야기를합니다.
ToolmakerSteve

145

매직 넘버는 하드 코딩 된 값으로 나중에 변경 될 수 있지만 업데이트하기가 어려울 수 있습니다.

예를 들어 "주문"개요 페이지에 마지막 50 개의 주문을 표시하는 페이지가 있다고 가정합니다. 50은 매직 넘버입니다. 표준 또는 컨벤션을 통해 설정되지 않았기 때문에 스펙에 설명 된 이유로 만든 숫자입니다.

이제 SQL 스크립트 ( SELECT TOP 50 * FROM orders), 웹 사이트 (최근 50 주문), 주문 로그인 ( for (i = 0; i < 50; i++)) 및 다른 많은 장소와 같은 다른 장소에 50 개가 있습니다.

이제 누군가가 50에서 25로 변경하기로 결정하면 어떻게됩니까? 또는 75? 또는 153? 이제 모든 장소에서 50을 교체해야하며 놓칠 가능성이 큽니다. 50은 다른 용도로 사용될 수 있기 때문에 찾기 / 바꾸기가 작동하지 않을 수 있으며, 맹목적으로 50을 25로 바꾸면 부작용이 발생할 수 있습니다 (예 : Session.Timeout = 50통화도 25로 설정되고 사용자가 너무 자주 시간 초과보고를 시작 함).

또한 코드가 이해하기 어려울 수 있습니다. 즉, " if a < 50 then bla"-복잡한 함수 도중에이 코드를 발견하면 코드에 익숙하지 않은 다른 개발자가 "WTF는 50 ???"

그렇기 const int NumOrdersToDisplay = 50때문에 코드를 더 읽기 쉽도록 ( " if a < NumOrdersToDisplay") 명확하게 정의 된 1 개 위치에서만 변경 하면되기 때문에 "1"- " " 와 같이 모호하고 임의의 숫자를 갖는 것이 가장 좋습니다 .

마법의 숫자는 적절한 장소가 표준을 통해 정의 된 모든 것, 즉 SmtpClient.DefaultPort = 25TCPPacketSize = whatever(즉,이 표준화하지 않도록 경우). 또한 1 함수 내에서만 정의 된 모든 것이 허용 될 수는 있지만 상황에 따라 다릅니다.


18
변경할 수 없더라도 무슨 일이 일어나고 있는지 명확하지 않기 때문에 여전히 나쁜 생각입니다.
Loren Pechtel

11
항상 명확하지는 않습니다. SmtpClient.DefaultPort = 25아마도 분명하다 보다 SmtpClient.DefaultPort = DEFAULT_SMTP_PORT.
user253751

4
@immibis DEFAULT_SMTP_PORT 개념을 사용하는 다른 코드가 전혀 없다고 가정합니다. 해당 응용 프로그램의 기본 SMTP 포트가 변경되면 여러 위치에서 업데이트해야 불일치가 발생할 수 있습니다.
Russ Bradberry

3
또한 모든 사용법을 찾기가 더 어렵 25습니다. 응용 프로그램 전체 를 검색 25하고 SMTP 포트에 대한 항목 만 변경해야합니다. 예를 들어 테이블 열의 너비 나 숫자와 같은 25는 아닙니다. 페이지에 표시 할 레코드 수
Michael Stum

2
이 예제에서는 코드가 25가 아닌 SmtpClient.DefaultPort를 사용하기를 기대합니다. 따라서 한 곳에서 변경하면됩니다. 그리고 포트 번호는 동일하게 유지 될 가능성이 높습니다. 임의의 매직 번호가 아니라에 의해 지정된 번호 IANA입니다.
njsg 2016 년

34

마법 번호 에 대한 Wikipedia 항목을 살펴 보셨습니까 ?

매직 넘버 레퍼런스가 만들어지는 모든 방법에 대해 조금 자세하게 설명합니다. 나쁜 프로그래밍 연습으로 마술 번호에 대한 인용문은 다음과 같습니다.

매직 넘버라는 용어는 또한 설명없이 소스 코드에서 직접 숫자를 사용하는 나쁜 프로그래밍 방식을 말합니다. 대부분의 경우 이로 인해 프로그램을 읽고 이해하고 유지하기가 더 어려워집니다. 대부분의 안내서는 숫자 0과 1을 제외하지만 코드의 다른 모든 숫자를 명명 된 상수로 정의하는 것이 좋습니다.


8
RTFW의 좋은 예 :)
Eva

나는 대답이 꽉 찼다 고 말하고 싶습니다.
Skeeve

25

매직 넘버 대 기호 상수 : 교체시기

마법 : 알 수없는 의미

Symbolic Constant-> 올바른 의미 및 올바른 컨텍스트를 제공합니다

시맨틱 : 사물의 의미 또는 목적.

"상수를 작성하고 의미 뒤에 이름을 지정한 다음 숫자로 바꾸십시오." -마틴 파울러

첫째, 매직 넘버는 단순한 숫자가 아닙니다. 모든 기본 값은 "마법"이 될 수 있습니다. 기본 값은 정수, 실수, double, float, 날짜, 문자열, 부울, 문자 등과 같은 매니페스트 엔터티입니다. 문제는 데이터 유형이 아니라 코드 텍스트에 나타나는 값의 "마법"측면입니다.

"마술"은 무엇을 의미합니까? 정확하게하기 위해 : "마법"에 의해, 우리는 코드의 맥락에서 가치의 의미 (의미 또는 목적)를 가리 키려고합니다. 알 수 없거나, 알 수 없거나, 불분명하거나 혼동된다. 이것이 "마술"의 개념입니다. 특별한 의미의 단어 (예 : 기호 상수)없이 서라운드 컨텍스트에서 의미 론적 의미 또는 목적이 빠르고 쉽게 알려지고 명확하고 이해 (혼동되지 않음) 할 때 기본 값은 마술이 아닙니다.

따라서, 우리는 주변 환경으로부터 기본 가치의 의미와 목적을 알고, 명확하게 이해하는 코드 리더의 능력을 측정하여 마법의 숫자를 식별합니다. 독자가 덜 알려지고 덜 명확하고 더 혼란 스러울수록 기본 값이 "매직"입니다.

유용한 정의

  • 혼동 : (누군가) 당황하거나 당황하게 만듭니다.
  • 당황 : (누군가) 당황하고 혼란하게합니다.
  • 당황 : 완전히 당황; 매우 당황했다.
  • 당황 : 완전히 어리둥절하거나 당황합니다.
  • 의아해 : 이해할 수없는; 황당한가요.
  • 이해 : 의도 된 의미 (단어, 언어 또는 화자)를 인식합니다.
  • 의미 : 단어, 텍스트, 개념 또는 행동의 의미
  • 의미 : (특정한 것 또는 개념)을 전달, 표시 또는 언급하려는 의도; 의미합니다.
  • 서명하다 : 표시한다.
  • 표시 : 무언가를 나타내는 표시 또는 정보.
  • 표시 : 지적; 보여 주다.
  • 부호 : 존재 또는 발생이 다른 존재의 존재 또는 발생을 나타내는 객체, 품질 또는 이벤트.

기초

마법의 기본 가치에 대한 두 가지 시나리오가 있습니다. 프로그래머와 코드에서 두 번째 만이 가장 중요합니다.

  1. 그 의미를 알 수 없거나 알 수 없거나 불분명하거나 혼동되는 고독한 기본 값 (예 : 숫자)
  2. 문맥 상 기본 값 (예 : 숫자)이지만 그 의미는 알 수 없거나 알 수 없거나 불분명하거나 혼동됩니다.

"매직"에 대한 가장 중요한 의존성은 고독한 기본 값 (예 : 숫자)이 일반적으로 알려진 의미론 (예 : Pi)을 갖지 않지만, 로컬에서 알려진 의미론 (예 : 프로그램)을 가지므로 문맥에서 완전히 명확하지 않거나 악용 될 수 있습니다. 좋은 또는 나쁜 맥락에서.

대부분의 프로그래밍 언어의 의미는 (아마도) 데이터 (예 : 데이터 테이블)를 제외하고 고독한 기본 값을 사용할 수 없습니다. 우리가 "마법의 숫자"를 만날 때 우리는 일반적으로 맥락에서 그렇게합니다. 따라서

"이 마법 번호를 기호 상수로 대체합니까?"

입니다 :

"컨텍스트에서 숫자의 의미 적 의미 (거기에 대한 목적)를 얼마나 빨리 평가하고 이해할 수 있습니까?"

마술의 종류, 그러나 꽤

이러한 생각을 염두에두고 적절한 맥락에 배치 할 때 Pi (3.14159)와 같은 숫자가 어떻게 "마법의 숫자"가 아닌지 빠르게 알 수 있습니다 (예 : 2 x 3.14159 x 반경 또는 2 * Pi * r). 여기서 숫자 3.14159는 기호 상수 식별자없이 정신적으로 Pi로 인식됩니다.

여전히, 우리는 일반적으로 3.14159를 숫자의 길이와 복잡성 때문에 Pi와 같은 기호 상수 식별자로 대체합니다. Pi의 길이와 복잡성의 측면 (정확도의 필요성과 결합)은 일반적으로 기호 식별자 또는 상수가 오류가 덜 발생한다는 것을 의미합니다. "Pi"를 이름으로 인식하는 것은 단순히 편리한 보너스이지만 상수를 갖는 주된 이유는 아닙니다.

한편 : 목장에서

Pi와 같은 일반적인 상수를 제외하고는 주로 특별한 의미를 가진 숫자에 중점을 두지 만 그 의미는 소프트웨어 시스템의 세계에 제약을받습니다. 이러한 숫자는 "2"(기본 정수 값) 일 수 있습니다.

숫자 2를 단독으로 사용하는 경우 첫 번째 질문은 "2"는 무엇을 의미합니까? "2"자체의 의미는 문맥 없이는 알 수없고 알 수 없으므로 사용이 불분명하고 혼동됩니다. 언어 의미 때문에 소프트웨어에 "2"만있는 것은 아니지만 "2"자체에는 특별한 의미가 없거나 명백한 목적 만 가지고 있지 않습니다.

우리의 고독한 "2"를 다음과 같은 맥락에 두자. padding := 2문맥이 "GUI 컨테이너"인 . 이와 관련하여 2의 의미 (픽셀 또는 기타 그래픽 단위)는 의미 (의미 및 목적)를 빠르게 추측 할 수있게합니다. 우리는 여기서 멈추고이 맥락에서 2가 괜찮다고 말할 수 있으며 우리가 알아야 할 것이 없습니다. 그러나 아마도 우리의 소프트웨어 세계에서 이것은 전체 이야기가 아닙니다. 그것에 더 많은 것이 있지만, 문맥으로 "padding = 2"는 그것을 드러 낼 수 없습니다.

우리 프로그램에서 2 개의 픽셀 패딩이 시스템 전체에서 "default_padding"다양성을 가지고 있다고 가정 해 봅시다. 따라서 지시를 작성하는 padding = 2것만으로는 충분하지 않습니다. "기본"의 개념은 공개되지 않습니다. 내가 쓸 때 : padding = default_padding문맥으로 그리고 다른 곳에서 : default_padding = 2나는 우리 시스템에서 2의 더 나은 의미 (의미 적 및 목적)를 완전히 실현합니까?

위의 예는 "2"자체만으로도 가능하기 때문에 꽤 좋습니다. "내 프로그램" default_padding의 GUI UX 부분에 2가있는 "내 프로그램"으로 이해의 범위와 영역을 제한 할 때만 , 적절한 문맥에서 "2"를 이해해야합니다. 여기서 "2"는 "마법의"숫자이며, default_padding"내 프로그램"의 GUI UX 컨텍스트 내에서 기호 상수를 고려 default_padding하여 묶는 코드의 더 큰 컨텍스트에서 빠르게 이해할 수 있도록 사용 합니다.

따라서 의미 (의미 및 목적)를 충분하고 신속하게 이해할 수없는 모든 기본 값은 기본 값 (예 : 마법 수) 대신 기호 상수에 적합한 후보입니다.

더 나아 가기

스케일의 숫자에도 의미가있을 수 있습니다. 예를 들어, 우리가 괴물이라는 개념을 가지고있는 D & D 게임을하는 것처럼 가장하십시오. 우리의 괴물 객체는 life_force정수 라는라는 기능을 가지고 있습니다. 숫자에는 의미를 제공 할 단어가 없으면 알 수 없거나 명확한 의미가 있습니다. 따라서 우리는 임의로 다음과 같이 말합니다.

  • full_life_force : INTEGER = 10-매우 살아 있음 (그리고 아프지 않음)
  • minimum_life_force : INTEGER = 1-간신히 살아 남음 (매우 손상됨)
  • 사망 : INTEGER = 0-사망
  • 언데드 : INTEGER = -1-최소 언데드 (거의 사망)
  • 좀비 : 정수 = -10-최대 언데드 (매우 언데드)

위의 상징적 인 상수로부터, 우리는 D & D 게임에서 우리의 몬스터에 대한 생존, 사망 및 "언데드"(그리고 가능한 결과 또는 결과)에 대한 정신적 인 그림을 얻기 시작합니다. 이 단어들 (기호 상수)이 없으면, 우리는 ~에 이르는 숫자들만 남게됩니다 -10 .. 10. 게임의 다른 부분이 무엇인지와 같은 다양한 작업의 숫자 수단의 범위에 대한 종속성이있는 경우 가능성이 큰 혼란의 장소에있는 단어 잎 우리없이 잠재적으로 우리의 게임에 오류가 그냥 범위 attack_elvesseek_magic_healing_potion.

따라서 "매직 숫자"의 대체를 검색하고 고려할 때 우리는 소프트웨어의 맥락에서 숫자와 숫자가 의미 적으로 상호 작용하는 방식에 대해 매우 의도적으로 채워진 질문을하고 싶습니다.

결론

어떤 질문을해야하는지 검토해 보겠습니다.

다음과 같은 경우 마법 번호가있을 수 있습니다 ...

  1. 기본 가치가 소프트웨어 세계에서 특별한 의미 나 목적을 가질 수 있습니까?
  2. 특수한 의미 나 목적이 적절한 상황에서도 알려지지 않거나 알 수 없거나 불분명하거나 혼동 될 수 있습니까?
  3. 올바른 기본 가치를 잘못된 맥락에서 나쁜 결과로 부적절하게 사용할 수 있습니까?
  4. 부적절한 기본 가치가 올바른 맥락에서 나쁜 결과를 초래할 수 있습니까?
  5. 기본 값이 특정 상황에서 다른 기본 값과 의미 또는 목적 관계가 있습니까?
  6. 각각의 의미가 다른 코드에서 둘 이상의 위치에 기본 값이 존재할 수있어 독자에게 혼란을 줄 수 있습니까?

코드 텍스트에서 독립형 매니페스트 상수 기본 값을 검사하십시오. 그러한 가치의 각 사례에 대해 천천히 그리고 신중하게 질문하십시오. 답의 힘을 고려하십시오. 여러 번 대답은 흑백이 아니지만 의미와 목적, 학습 속도 및 이해 속도를 잘못 이해하는 음영이 있습니다. 또한 소프트웨어 소프트웨어가 주변의 소프트웨어 시스템에 어떻게 연결되어 있는지 확인해야합니다.

결국, 대체에 대한 대답은 독자의 강점 또는 약점의 측정치 (당신의 마음에)에 답하여 연결을 만드는 것입니다 (예 : "얻습니다"). 의미와 목적을 더 빨리 이해할수록 "마법"이 적습니다.

결론 : 마법이 혼동으로 인해 발생하는 버그를 감지하기 어려울 정도로 큰 경우에만 기본 값을 기호 상수로 대체하십시오.


1
감사. 동료들이 계속 설치하는 정적 분석 도구에 마법의 숫자에 대한 불만이 계속 있습니다. 결과적으로 모든 기본 값이 기호 상수로 대체됩니다. 나는 당신의 결론에 동의 할 때 이것이 이상적이지 않다는 것을 알게됩니다.
Chomeh

17

매직 넘버는 파일 형식 또는 프로토콜 교환을 시작할 때 일련의 문자입니다. 이 번호는 상태 점검 기능을합니다.

예 : GIF 파일을 열면 시작 부분에 GIF89가 표시됩니다. "GIF89"는 매직 넘버입니다.

다른 프로그램은 파일의 처음 몇 문자를 읽고 GIF를 올바르게 식별 할 수 있습니다.

임의의 이진 데이터는 동일한 문자를 포함 할 수 있습니다. 그러나 매우 가능성이 낮습니다.

프로토콜 교환과 관련하여 전달 된 현재 '메시지'가 손상되었거나 유효하지 않음을 신속하게 식별 할 수 있습니다.

매직 넘버는 여전히 유용합니다.


13
나는 그가로 다스 려 된 매직 넘버 생각하지 않습니다
마르 Aguiar

4
추가 한 "file-format"및 "networking"태그는 해당 종류의 매직 번호에 대해 명확하게 이야기하지 않기 때문에 제거해야 할 수도 있습니다.
Landon

9
매직 넘버가 단순한 코드 문제 이상을 나타낼 수 있다는 것을 아는 것이 여전히 유용합니다. -아담
아담 데이비스에게

3
제목이 "소스 코드와 관련하여 마법의 숫자는 무엇입니까"라고 읽은 경우 태그가 없어야합니다. 그러나 그는 이것을 지정하지 않았습니다. 추가 정보를 얻는 것이 좋습니다. 카일, 랜든, 마르시오가 틀렸다고 생각합니다.
브라이언 R. 본디

4
그가 찾고있는 것을 결정할 방법도 없었습니다. 내가 첫 번째 글이었던 이래로 그가 어떤 글을 찾고 있는지 추측 할 수 없었습니다.
브라이언 R. 본디

12

프로그래밍에서 "마법의 숫자"는 상징적 인 이름을 부여해야하는 값이지만, 대신 일반적으로 여러 곳에서 리터럴로 코드에 삽입되었습니다.

SPOT (Single Point of Truth)이 좋은 것과 같은 이유로 나쁩니다. 나중에이 상수를 변경하려면 모든 인스턴스를 찾기 위해 코드를 찾아야합니다. 이 숫자가 무엇을 나타내는 지 다른 프로그래머에게 명확하지 않을 수 있기 때문에 "나쁜"마법이기도합니다.

사람들은 때때로 이러한 상수를 별도의 파일로 이동하여 구성으로 작동함으로써 마법 번호를 더 이상 제거하지 않습니다. 이것은 때때로 도움이되지만 가치보다 더 복잡해질 수도 있습니다.


왜 매그넘 숫자를 제거하는 것이 항상 좋은지에 대해 더 구체적으로 설명 할 수 있습니까?
Marcio Aguiar

PI ^ E = 0 + 1과 같은 수학 식
러드 업다이크

5
마르시오 : "const int EIGHT = 8;" 그런 다음 요구 사항이 변경되고 "const int EIGHT = 9;"
jmucchiello

6
죄송하지만 이는 단순히 이름이 잘못되었거나 상수에 대한 기본 사용법의 예입니다.
Kzqai

1
@MarcioAguiar : 일부 플랫폼에서는 (foo[i]+foo[i+1]+foo[i+2]+1)/3루프보다 훨씬 빠른 식이 평가 될 수 있습니다. 3코드를 루프로 다시 작성하지 않고 교체하는 경우 ITEMS_TO_AVERAGE정의 된 것을 본 사람은 코드를 3변경하여 5평균 더 많은 항목을 가질 수 있다고 생각할 수 있습니다 . 대조적으로, 문자와 함께 발현에보고있는 사람은 3(가) 실현 것이다 3합산되는 항목의 수를 나타낸다.
supercat

10

매직 넘버는 또한 특수한 하드 코딩 된 시맨틱을 가진 숫자 일 수도 있습니다. 예를 들어, 레코드 ID> 0이 정상적으로 처리되고 0 자체가 "새 레코드"이고 -1이 "이것이 루트"이고 -99가 "이것이 루트에 작성 됨"인 시스템을 본 적이 있습니다. 0과 -99는 WebService가 새 ID를 제공하게합니다.

나쁜 점은 특별한 능력을 위해 공백 (레코드 ID의 부호있는 정수)을 재사용한다는 것입니다. ID 0 또는 음수 ID를 사용하여 레코드를 만들지 않을 수도 있지만, 그렇지 않더라도 코드 나 데이터베이스를 보는 모든 사람이이 문제를 발견하고 처음에는 혼란 스러울 수 있습니다. 그 특별한 가치가 잘 문서화되지 않았다는 것은 말할 나위도 없습니다.

틀림없이, 22, 7, -12 ~ 620 도 매직 넘버로 계산. ;-)


10

마법의 숫자를 사용하여 언급되지 않은 문제 ...

당신이 그들 중 많은 것을 가지고 있다면, 당신이 이 같은 곳에서 마술 숫자를 사용하는 두 가지 다른 목적 을 가지고 있다는 것이 합리적 입니다.

그런 다음, 한 가지 목적으로 만 값을 변경해야합니다.


이것은 숫자에 관해 이야기 할 때 가능성이있는 것처럼 보이지는 않지만 (적어도 나에게는 그렇지는 않습니다), 나는 문자열로 그것을 쳤습니다. 내가 좋아하는 취미가 아닌 다른 것들에 사용되고 있다는 것을 알아야합니다.
Tomislav Nakic-Alfirevic

4

나는 이것이 당신의 이전 질문에 대한 나의 대답 에 대한 응답이라고 가정합니다 . 프로그래밍에서, 매직 넘버는 설명없이 나타나는 내장 숫자 상수입니다. 두 개의 다른 위치에 표시되면 한 인스턴스가 변경되고 다른 인스턴스가 아닌 상황이 발생할 수 있습니다. 이 두 가지 이유로 인해, 사용되는 곳 이외의 숫자 상수를 분리하고 정의하는 것이 중요합니다.


3

저는 항상 "매직 넘버"라는 용어를 다르게 사용했습니다. 빠른 유효성 검사로 확인할 수있는 데이터 구조 내에 저장된 모호한 값입니다. 예를 들어 gzip 파일은 처음 3 바이트로 0x1f8b08을 포함하고 Java 클래스 파일은 0xcafebabe로 시작합니다.

파일이 다소 난잡하게 전송되고 생성 방식에 대한 메타 데이터가 손실 될 수 있기 때문에 파일 형식에 포함 된 매직 넘버가 종종 표시됩니다. 그러나 매직 넘버는 ioctl () 호출과 같은 메모리 내 데이터 구조에도 사용됩니다.

파일 또는 데이터 구조를 처리하기 전에 매직 번호를 빠르게 확인하면 입력이 완료되었다는 것을 알리기 위해 잠재적으로 긴 처리 과정을 거치지 않고 오류를 조기에 알릴 수 있습니다.


2

때로는 코드에 구성 할 수없는 "하드 코딩 된"숫자를 원할 수도 있습니다. 최적화 된 역 제곱근 알고리즘에 사용되는 0x5F3759DF를 포함 하여 많은 유명한 것들이 있습니다 .

드문 경우에 그러한 매직 넘버를 사용해야 할 필요가있는 경우, 코드에서 그것들을 const로 설정하고 그것들이 사용되는 이유, 작동 방식 및 출처를 문서화합니다.


1
내 생각에, 매직 넘버 코드 냄새는 구체적으로 설명 할 수없는 상수 를 말합니다 . 명명 된 상수에 넣는 한 문제가되지 않습니다.
돈 커크비

2

클래스 상단의 변수를 기본값으로 초기화하는 것은 어떻습니까? 예를 들면 다음과 같습니다.

public class SomeClass {
    private int maxRows = 15000;
    ...
    // Inside another method
    for (int i = 0; i < maxRows; i++) {
        // Do something
    }

    public void setMaxRows(int maxRows) {
        this.maxRows = maxRows;
    }

    public int getMaxRows() {
        return this.maxRows;
    }

이 경우 15000은 마법 번호입니다 (CheckStyles에 따름). 나에게 기본값을 설정하는 것은 괜찮습니다. 나는하고 싶지 않다 :

private static final int DEFAULT_MAX_ROWS = 15000;
private int maxRows = DEFAULT_MAX_ROWS;

읽기가 더 어려워 집니까? CheckStyles를 설치하기 전까지는 이것을 고려하지 않았습니다.


생성자가 값을 초기화하면 괜찮을 것이라고 생각합니다. 그렇지 않으면 값이 생성자 외부에서 초기화되면 번거롭고 읽기 어려운 것으로 간주됩니다.
토마스 에딩

static final한 가지 방법으로 상수를 사용하면 상수가 과도 하다고 생각 합니다. final메소드 상단에 선언 된 변수는 더 읽기 쉬운 IMHO입니다.
Eva

0

@ eed3si9n : 심지어 '1'은 마법의 숫자라고 제안합니다. :-)

매직 넘버와 관련된 원칙은 코드가 다루는 모든 사실이 정확히 한 번 선언되어야한다는 것입니다. 코드에 마술 숫자 (예 : @marcio가 제공 한 암호 길이 예제)를 사용하면 해당 사실을 쉽게 복제 할 수 있으며 해당 사실을 이해하면 유지 관리 문제가 발생합니다.


5
IOW 코드는 다음과 같이 작성해야합니다.factorial n = if n == BASE_CASE then BASE_VALUE else n * factorial (n - RECURSION_INPUT_CHANGE); RECURSION_INPUT_CHANGE = 1; BASE_CASE = 0; BASE_VALUE = 1
Thomas Eding

0

반환 변수는 어떻습니까?

저장 프로 시저를 구현할 때 특히 어려운 점이 있습니다. .

다음 저장 프로 시저를 상상해보십시오 (잘못된 구문, 예를 보여주기 위해 알고 있습니다).

int procGetIdCompanyByName(string companyName);

특정 테이블에 존재하면 회사의 ID를 반환합니다. 그렇지 않으면 -1을 반환합니다. 어떻게 든 그것은 마법의 숫자입니다. 지금까지 읽은 권장 사항 중 일부는 실제로 이와 같은 디자인을 수행해야한다고 말합니다.

int procGetIdCompanyByName(string companyName, bool existsCompany);

그런데 회사가 존재하지 않으면 무엇을 반환해야합니까? Ok : existesCompanyfalse 로 설정하고 -1도 반환합니다.

Antoher 옵션은 두 가지 기능을 수행하는 것입니다.

bool procCompanyExists(string companyName);
int procGetIdCompanyByName(string companyName);

따라서 두 번째 저장 프로 시저의 전제 조건은 회사가 존재한다는 것입니다.

그러나이 시스템에서는 다른 사용자가 회사를 만들 수 있기 때문에 동시성이 두렵습니다.

결론은 다음과 같습니다. 상대적으로 알려져 있고 안전한 어떤 종류의 "매직 숫자"를 사용하여 무언가가 성공하지 못했거나 존재하지 않는다는 것을 어떻게 생각하십니까?


이 경우 함수의 문서에 음수 반환 값이 회사를 찾을 수 없다는 의미가 있으면 상수를 사용할 이유가 없습니다.
Vincent Fourmond

-1

상수로 매직 넘버를 추출하는 또 다른 장점은 비즈니스 정보를 명확하게 문서화 할 수있는 가능성을 제공합니다.

public class Foo {
    /** 
     * Max age in year to get child rate for airline tickets
     * 
     * The value of the constant is {@value}
     */
    public static final int MAX_AGE_FOR_CHILD_RATE = 2;

    public void computeRate() {
         if (person.getAge() < MAX_AGE_FOR_CHILD_RATE) {
               applyChildRate();
         }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.