모든 매직 넘버가 동일하게 만들어 집니까?


77

최근 프로젝트에, 나는 바이트로 변환하는 데 필요한 킬로바이트의 키비 바이트 . 코드는 간단했다 :

var kBval = byteVal / 1024;

그것을 작성한 후, 나머지 기능이 작동하고 진행되었습니다.

그러나 나중에 코드에 마법 번호를 삽입했는지 궁금해하기 시작했습니다 . 내 일부는 숫자가 고정 상수이므로 쉽게 이해해야하기 때문에 괜찮다고 말합니다. 그러나 내 다른 부분은 정의 된 상수에 싸여 있으면 명확했을 것이라고 생각합니다 BYTES_PER_KBYTE.

상수로 잘 알려진 숫자가 실제로 마법과 같은 것이 아닌가?


관련 질문 :

숫자는 마법의 숫자는 언제입니까? 그리고 코드의 모든 번호는 "매직 넘버"으로 간주되어 있습니까? -비슷하지만 내가 묻는 것보다 훨씬 광범위한 질문입니다. 내 질문은 그 질문에서 다루지 않은 잘 알려진 상수에 중점을 둡니다.

매직 넘버 제거 : 언제 "아니오"라고 말할 때입니까? 또한 관련이 있지만 상수가 마법의 숫자인지 아닌지에 대한 리팩토링에 중점을 둡니다.


17
실제로는 상수와 같은 상수를 만든 프로젝트에서 작업했습니다 FOUR_HUNDRED_FOUR = 404. 리터럴 대신 상수 문자열을 사용하는 데 익숙한 또 다른 프로젝트를 진행 했으므로 코드에 수십 줄이 생겼습니다.DATABASE = "database"
Rob

82
1024그렇지 않으면 개발자 팀이 "kilobytes"또는 "kibibytes"에 대해 논쟁하는 데 모든 시간을 할애하기 때문에 확실히 사용 하십시오.
Steven Burnap

6
당신은 1024 키비는 것을 고려하고 있습니다 #define KIBI, 1024 MEBI* 1024 1024 ...
ysdx

6
@Rob Y : 좋은 옛날 포트란 프로그래머처럼 들립니다. 그 프로그래밍 언어 프로그래머가 그렇게하도록 강요 했기 때문입니다. 그렇습니다. ZERO=0, ONE=1, TWO=2프로그램이 다른 언어로 포팅 될 때 (또는 프로그래머가 언어를 전환 할 때 동작을 변경하지 않는 등) 상수가 표시 될 것입니다. 또한 해당 언어를 볼 수 있으며 누군가가 변경하지 않도록 기도 해야합니다 ONE=2.
Holger

4
@NoctisSkytower 우리 팀은 우리가 사용하는 여러 언어와 해당 언어에서 일관성이없는 구현으로 인해 비트 이동 연산자 대신 명시 적 구분 문을 사용하는 것을 선호합니다. 마찬가지로, 음수 값은 비트 단위 시프트와 일관되지 않게 처리됩니다. 반드시 음의 바이트 값을 가질 필요는 없지만 변환하는 다른 측정 단위를 사용하면 음의 값을 가질 수 있습니다.

답변:


103

모든 매직 넘버가 같은 것은 아닙니다.

그 경우에는 그 상수가 정상이라고 생각합니다. 매직 넘버의 문제점은 이들이 매직 일 때입니다. 즉, 그 기원이 무엇인지, 왜 값이 왜인지, 또는 값이 정확한지 확실하지 않습니다.

BYTES_PER_KBYTE 뒤에 1024를 숨기면 정확한지 여부를 즉시 볼 수 없습니다.

바이트 값을 메가 바이트로 변환하는 경우 상수 1,048,576이 1024 ^ 2로 명확하지 않기 때문에 BYTES_PER_MBYTE 또는 이와 유사한 상수를 정의합니다. 심지어는 정확합니다.

한 곳에서만 사용되는 요구 사항 또는 표준에 의해 지정된 값에 대해서도 마찬가지입니다. 나는 다른 곳에서 그것을 정의하고 두 부분을 쫓아내는 것보다 다루기 쉽도록 관련 소스에 대한 주석으로 상수를 올바르게 배치하는 것을 발견했습니다.

// Value must be less than 3.5 volts according to spec blah.
SomeTest = DataSample < 3.50

나보다 더 잘 찾아

SomeTest = DataSample < SOME_THRESHOLD_VALUE

SOME_THRESHOLD_VALUE여러 곳에서 사용될 때만 트레이드 오프가 상수를 정의 할 가치가 있다고 생각합니다.


67
"그들이 마법 때 매직 넘버의 문제입니다"-이다 그런 그 개념의 화려한 설명! 난 진지해! 그 문장만으로 +1.
Jörg W Mittag

20
제가 방금 생각 해낸 것은 다음과 같습니다. "문제가되는 숫자가 아니라 마법입니다."
Jörg W Mittag

10
1024는 누구에게 명백한가? 모든 매직 넘버에 대한 칭의가 아닙니까? 모든 매직 넘버는 누구에게나 쓰 였기 때문에 사용됩니다. 9.8도 명확하지 않습니까? 나에게는 그것이 지구상의 중력 가속이라는 것이 명백하지만 그럼에도 불구하고 나는 상수를 만들 것입니다.
Tulains Córdova

15
아니요. "더 나은"예제에서 언급 한 것과 같은 주석은 거대한 적기입니다. 당시에 작성한 사람의 가독성 테스트를 통과하지 못하는 코드입니다. 예를 들어 보겠습니다. e^i*pi = -1보다 훨씬 더 명확 2.718^i*3.142 = -1합니다. 변수는 중요하며 일반적인 코드만을위한 것이 아닙니다. 코드는 먼저 읽고 두 번째 컴파일을 위해 작성됩니다. 또한 사양이 많이 바뀝니다. 1024는 아마도 설정에 없어야하지만 3.5 소리는 있어야합니다.
Nathan Cooper

51
1024 ^ 2에도 상수를 사용하지 않을 것입니다. 1024*1024PLZ!
궤도에서 가벼움 경주

44

마법의 숫자에 관해서는 두 가지 질문이 있습니다.

번호는 이름이 있습니까?

이름은 이름을 읽고 그 뒤에있는 숫자의 목적을 이해할 수 있기 때문에 유용합니다. 명명 상수 수 있습니다 이름은 대체 수보다 이해하기 쉽게 경우 가독성을 향상 하고 상수 이름은 간결하다.

분명히, pi, e 등의 상수. 의미있는 이름이 있습니다. 1024와 같은 값이 될 수도 BYTES_PER_KB있지만 모든 개발자가 1024의 의미를 알 것으로 기대합니다. 소스 코드의 독자는 두 가지의 다양한 힘을 알고 배경을 알아야하는 전문 프로그래머입니다.

여러 위치에서 사용됩니까?

이름은 상수의 한 강점이지만 다른 하나는 재사용 성입니다. 값이 변경 될 수있는 경우 여러 위치에서 값을 찾아야하는 대신 한 곳에서 변경할 수 있습니다.

당신의 질문

귀하의 질문의 경우, 나는 숫자를 그대로 사용합니다.

이름 : 해당 번호의 이름이 있지만 실제로 유용한 것은 없습니다. 요구 사항 문서에 지정된 수학 상수 또는 값을 나타내지 않습니다.

위치 : 여러 위치에서 사용하더라도 변경되지 않으므로이 이점을 무시할 수 있습니다.


1
매직 넘버 대신 상수를 사용하는 이유는 상기 숫자가 변경 될뿐 아니라 가독성과 자체 문서화를위한 것입니다.
Tulains Córdova

4
@ user61852 : 명명 된 상수가 항상 더 읽기 쉬운 것은 아닙니다. 그들은 종종 있지만 항상 그런 것은 아닙니다.
whatsisname

2
개인적으로 저는이 두 가지 질문을 대신 사용합니다. "이 값이 프로그램 수명 기간 동안 변경 될까요?" "이 소프트웨어로 작업 할 것으로 예상되는 개발자가이 숫자가 무엇인지 이해할 수 있습니까?"
Steven Burnap

4
Y2K 문제를 의미합니까? 그것이 관련이 있는지 확실하지 않습니다. 예, 'date-1900'과 같은 많은 코드가 있었지만 해당 코드에서 문제는 마법의 숫자 "1900"이 아니 었습니다.
Steven Burnap

1
이 답변은 1024 개의 숫자 중 하나 인 "명백한"숫자는 다른 개발자가 이름이 지정된 상수를 정의 하더라도 자발적으로 숫자로 쓸 가능성이 높다는 언급에서 도움이 될 수 있습니다. 하나의 가능성에 대한 난 이미 내가하지 않았다 경우 1024 일정 기존의 소스 코드를 검색 생각하지 않을 알고 내가 바이트 양 변환 1024을 사용하는 데 필요한 경우, 하나가있다.
하이드

27

이 인용문

문제의 숫자가 아니라 마법입니다.

말했듯 에 의해 르그 W MITTAG 아주 잘이 질문에 대한 대답.

일부 숫자는 특정 상황에서 마술이 아닙니다. 질문에 제공된 예제에서 측정 단위는 변수 이름으로 지정되었으며 수행중인 작업은 매우 명확했습니다.

그래서 1024문맥이 전환에 사용하는 적절한 상수 값의 매우 명확 것을 만들기 때문에 마법이 아니다.

마찬가지로 다음과 같은 예가 있습니다.

var numDays = numHours / 24; 

하루 24 시간이 있다는 것을 잘 알고 있기 때문에 똑같이 명확하고 마술이 아닙니다.


21
하지만 ...하지만 ... 24는 바뀔 수 있습니다! 지구의 회전 속도느려지고 결국 25 시간이 걸립니다! (물론 우리는 그때까지 모두 죽었을 것이며, 그 소프트웨어를 다른 사람의 문제로 유지 보수 할 것입니다)

14
소프트웨어가 화성에 배포 된 후 어떻게됩니까 ? 당신은 그 상수를 주입해야합니다 ...
durron597

8
@ durron597 : 만약 그 시간 동안 지구가 느려질만큼 프로그램이 오래 실행된다면 어떨까요 ? 상수를 주입해서는 안됩니다. 타임 스탬프 (현재 기본값)를 수락하고 타임 스탬프가 떨어지는 날의 시간 수를 반환하는 함수입니다. ;-)
Steve Jessop

13
나중에 YAGNI를 배워야합니다.
whatsisname

3
@ durron597 화성에 당신의 계시 소프트웨어가 배치 될 때 특별한 일은 발생하지 않습니다. 왜냐하면 화성에 따르면 화성 일은 24 시간 길지만, 각 시간은 지구보다 2.7 % 길기 때문입니다 . 물론 지구의 비현실적인 날이나 지구의 태양 일이 정확히 24 시간 (정확한 숫자는 같은 페이지에 있음)이 아니므로 24 어쨌든 사용할 수 없습니다 ! 이즈 카타가 언급했듯이 윤초는 아프다. 어쩌면 24지구보다 화성 에서 상수 를 실제로 사용하는 것이 더 좋을 것입니다!
CVn

16

다른 포스터는 전환이 '분명하다'고 언급했지만 동의하지 않습니다. 이 시점에서 원래 질문은 다음과 같습니다.

킬로바이트 kibibytes를

그래서 나는 이미 저자가 혼란 스러웠다는 것을 알고있다. Wikipedia 페이지가 혼란에 추가됩니다.

1000 = KB kilobyte (metric)
1024 = kB kilobyte (JEDEC)
1024 = KiB kibibyte (IEC)

따라서 "킬로바이트"는 1000과 1024의 요소를 의미하는 데 사용될 수 있으며, 'k'의 대문자 만 줄인 유일한 차이가 있습니다. 또한 1024는 킬로바이트 (JEDEC) 또는 키비 바이트 (IEC)를 의미 할 수 있습니다. 의미있는 이름을 가진 상수로 혼란을 완전히 산산조각 내십시오. BTW,이 스레드는 "BYTES_PER_KBYTE"를 자주 사용했으며 그 정도는 모호하지 않습니다. KBYTE : KIBIBYTE 또는 KILOBYTE입니까? 나는 JEDEC를 무시하고 선호 거라고 BYTES_PER_KILOBYTE = 1000하고 BYTES_PER_KIBIBYTE = 1024. 더 이상 혼란하지 않습니다.

나와 같은 사람들과 그 밖의 많은 사람들이 마법 번호의 이름을 지정하는 것에 대해 '무장 한'(여기에 주석을 달기 위해) 의견을 갖는 이유는 모두 당신이 하려는 일을 문서화하고 모호성을 제거하는 것입니다. 그리고 실제로 많은 혼란을 초래 한 유닛을 선택했습니다.

내가 볼 경우 :

int BYTES_PER_KIBIBYTE = 1024;  
...  
var kibibytes = bytes / BYTES_PER_KIBIBYTE;  

그런 다음 저자가 의도 한 바를 즉시 알 수 있으며 모호하지 않습니다. 상수는 초 안에 (다른 파일에 있더라도) 확인할 수 있으므로 '인스턴트'가 아니더라도 인스턴트 할 수있을 정도로 가깝습니다.

결국, 글을 쓸 때 분명 할 수 있지만 나중에 다시 올 때는 명확하지 않으며 다른 사람이 편집 할 때 덜 명확 할 수 있습니다. 상수를 만드는 데 10 초가 걸립니다. 단위 문제를 디버깅하는 데 30 분 이상이 걸릴 수 있습니다 (코드는 당신을 뛰어 넘지 않고 단위가 잘못되었다는 것을 말하지 않습니다, 당신은 그것을 알아 내기 위해 스스로 수학을해야합니다, 유닛을 확인하기 전에 10 개의 다른 길을 찾아야합니다).


2
좋은 답변입니다. 개별 팀 문화를 고려하면 더 강해집니다. 내 SE 프로필 을 믿었다면 , 나는 특정 표준을 앞질 정도로 나이가 들었습니다. 그래서 혼란은 "현재의 비표준 용어는 무엇입니까?" 그리고 당신은 내가 같은 용어 (비) 난이도를 가진 동료 공룡 팀과 함께 일한다고 가정하면 안전 할 것입니다.

@ GlenH7 : 2 개 단위의 제곱 단위로 할당되므로 2 개 단위의 제곱 단위 인 IMHO는 저장을 위해 보관해야합니다. 최소 할당 크기는 4096 바이트입니다. 최소 크기의 파일 256 개를 저장하는 데 필요한 저장 용량 또는 244.140625를 저장하는 데 필요한 저장 공간의 단위를 갖는 것이 더 합리적입니까? 개인적으로, 나는 하드 드라이브 제작자 메가 바이트와 다른 메가 바이트의 차이가 텔레비전 세트 대각선 인치와 실제 대각선 인치의 차이와 유사하다고 본다.
supercat

@Ryan :이 특정한 경우, 표준 단위의 채택에 대해 다소 무섭습니다. KB는 1000 바이트이거나 코드가 잘못되었고 1024 바이트가 KiB이거나 코드가 잘못되었습니다. 이것이 "단위가 모호합니다"문제를 극복 할 수있는 유일한 방법입니다. "마법 상수"(예 : 등 KB)를 다르게 정의하는 사람들 은 도움이되지 않습니다.
Brendan

11

숫자 값을 참조하여 이름을 정의하면 해당 이름을 사용하는 한 곳에서 다른 값이 필요할 때마다 그 이름이 필요할 수 있습니다. 또한 이름에 지정된 숫자 값을 변경하는 것이 값을 변경하는 합법적 인 방법이라고 제안하는 경향이 있습니다. 그러한 의미는 그것이 사실 일 때 유용하고 그것이 틀릴 때 위험 할 수 있습니다.

두 곳의 다른 장소에서 특정 리터럴 값 (예 : 1024)을 사용한다는 사실은 프로그래머가 변경을하도록하는 변경이 프로그래머가 다른 사람을 변경하기를 원할 가능성이 있지만 적용에 비해 영향이 훨씬 약하다는 것을 약하게 암시합니다 프로그래머가 그러한 상수에 이름을 할당 한 경우

이와 같은 주요 위험 은 코드를 수천 바이트 사용하는 안전한 방법이 명령문 을 변경하는 것이라고 생각하는 #define BYTES_PER_KBYTE 1024사람에게 발생할 수 printf("File size is %1.1fkB",size*(1.0/BYTES_PER_KBYTE));있다는 것 #define입니다. 그러나 다른 관련 코드가 KB 단위로 객체의 크기를 수신하고 버퍼를 할당 할 때 해당 상수를 사용하는 경우 이러한 변경은 비참 할 수 있습니다.

사용하기 적당한 수 있습니다 #define BYTES_PER_KBYTE_FOR_USAGE_REPORT 1024#define BYTES_PER_KBYTE_REPORTED_BY_FNOBULATOR 1024상수 1024에서 제공하는 모든 다른 목적을 위해 다른 이름을 지정하지만 정의와 정확히 한 번 익숙해 많은 식별자가 발생할 것입니다. 또한, 많은 경우에, 사용 된 코드를 볼 때 값이 무엇을 의미하는지 이해하는 것이 가장 쉽고, 사용 된 상수 값을 볼 때 코드가 어디를 의미하는지 알아내는 것이 가장 쉽습니다. 숫자 리터럴을 특정 목적으로 한 번만 사용하는 경우 리터럴을 사용하는 곳에 리터럴을 쓰면 레이블을 한 곳에 지정하고 다른 곳에 값을 사용하는 것보다 이해하기 쉬운 코드가 생성되는 경우가 많습니다.


7

나는 숫자 만 사용하는 것에 의존하지만, 한 가지 중요한 문제가 제기되지 않았다고 생각합니다. 같은 숫자는 다른 상황에서 다른 것을 의미 할 수 있으며, 이는 리팩토링을 복잡하게 할 수 있습니다.

1024는 MiB 당 KiB 수입니다. 1024를 사용하여 해당 계산을 어딘가 또는 여러 곳에서 나타내는 것으로 가정하고 대신 GiB를 계산하기 위해 해당 계산으로 변경해야한다고 가정합니다. 상수를 변경하는 것은 실수로 어떤 곳에서 잘못 변경하거나 다른 곳에서 놓칠 수있는 전역 찾기 / 바꾸기보다 쉽습니다.

또는 언젠가 업데이트해야하는 게으른 프로그래머가 도입 한 비트 마스크 일 수도 있습니다.

이것은 약간의 고안된 예이지만 일부 코드 기반에서는 새로운 요구 사항을 리팩토링하거나 업데이트 할 때 문제가 발생할 수 있습니다. 그러나이 특별한 경우, 특히 재사용 방법으로 계산을 묶을 수 있다면 평범한 숫자가 실제로 나쁜 형태라고 생각하지 않을 것입니다.

이름이 지정된 상수를 사용하는 경우 supercat에 따르면 컨텍스트가 중요한지 여부와 여러 이름이 필요한지 고려하는 것이 중요합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.