애플리케이션에 값을 하드 코딩하는 것이 좋은 생각입니까? 또는 이러한 유형의 값을 변경해야 할 경우를 대비하여 동적으로 호출하는 것이 항상 올바른 것입니까?
pi
애플리케이션에 값을 하드 코딩하는 것이 좋은 생각입니까? 또는 이러한 유형의 값을 변경해야 할 경우를 대비하여 동적으로 호출하는 것이 항상 올바른 것입니까?
pi
답변:
diameter = 2 * radius
또는 diameter = RADIUS_TO_DIAMETER_FACTOR * radius
? 실제로 매직 넘버가 더 나은 솔루션 일 수있는 코너 케이스가 있습니다.
diameter = radius << 1
합니까? 나는 또한 그럴 수 있다고 생각합니다 diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
.
diameter = radius.toDiameter()
지금까지이 Q & A에서 이상한 점을 발견 한 사람은 실제로 아무도 "하드 코드"또는 더 중요한 대안을 명확하게 정의하려고 시도하지 않았다는 것입니다.
TL; DR : 예, 그것은 이다 하드 코드 값에 좋은 생각이 가끔 있지만,에 관해서는 간단한 규칙이 없다 경우는 , 그것은 상황에 전적으로 달려 있습니다.
질문은 값을 좁히는 데 , 이는 마법의 숫자 를 의미 하지만, 그들이 좋은 아이디어인지 아닌지에 대한 대답 은 실제로 사용되는 것과 관련이 있습니다 !
"하드 코딩 된"값의 몇 가지 예는 다음과 같습니다.
구성 값
나는 같은 문장을 볼 때마다 울었다 command.Timeout = 600
. 왜 600입니까? 누가 결정 했습니까? 시간이 초과되어 누군가가 기본 성능 문제를 해결하는 대신 해킹으로 시간 초과를 제기 했습니까? 아니면 실제로 처리 시간에 대한 일부 알려진 문서화 된 기대입니까?
이들은 마법의 숫자 나 상수 가 아니 어야합니다. 최적의 값은 응용 프로그램이 실행되는 환경에 의해 대부분 또는 전적으로 결정되므로 의미있는 이름으로 구성 파일이나 데이터베이스에서 외부화해야합니다.
수학 공식
공식은 일반적으로 정적 인 경향이 있으므로 내부의 상수 값의 특성이 실제로 중요하지 않습니다. 피라미드의 부피는 (1/3) b * h입니다. 우리는 1 또는 3이 어디에서 왔는지 걱정합니까? 실제로는 아닙니다. 이전의 주석가는 diameter = radius * 2
아마 그보다 더 낫다고 지적 diameter = radius * RADIUS_TO_DIAMETER_CONVERSION_FACTOR
했지만 그것은 거짓 이분법입니다.
이 유형의 시나리오에서 수행해야 할 일은 함수를 작성하는 것 입니다. 나는 당신 이 공식을 어떻게 만들 었는지 알 필요는 없지만 여전히 그것이 무엇인지 알아야 합니다 . 위에서 쓴 넌센스 대신에 volume = GetVolumeOfPyramid(base, height)
갑자기 모든 것이 훨씬 명확 해지 며 함수 안에 마법의 숫자 ( return base * height / 3
)가 있으면 수식의 일부라는 것이 분명하기 때문에 완벽하게 괜찮습니다 .
열쇠는 여기에 가지고 물론이고 짧은 및 간단한 기능을. 10 개의 인수와 30 개의 계산 라인이있는 함수에서는 작동하지 않습니다. 이 경우 함수 구성 또는 상수를 사용하십시오.
도메인 / 비즈니스 규칙
이것은 값이 정확히 무엇인지에 따라 다르므로 항상 회색 영역입니다. 대부분 의 경우 상수로 변하는 후보가되는 이러한 특정 매직 번호입니다. 프로그램 논리를 복잡하게하지 않고도 프로그램을 더 쉽게 이해할 수 있기 때문입니다. 테스트 if Age < 19
대 if Age < LegalDrinkingAge
.; 당신은 아마도 상수없이 무슨 일이 일어나고 있는지 알아낼 수 있지만 설명적인 제목으로 더 쉽습니다.
이것들은 또한 예를 들어 함수 추상화의 후보가 될 수 있습니다function isLegalDrinkingAge(age) { return age >= 19 }
. 유일한 것은 비즈니스 로직이 그보다 훨씬 복잡하다는 것입니다. 각각 20-30 개의 매개 변수로 수십 개의 함수를 작성하는 것이 이치에 맞지 않을 수 있습니다. 객체 및 / 또는 함수를 기반으로 명확한 추상화가 없으면 상수를 사용하는 것이 좋습니다.
주의해야 할 점은 세무 부서에서 일하는 경우 실제로 부담스럽고 솔직하게 쓸 수 없게됩니다 AttachForm(FORM_CODE_FOR_SINGLE_TAXPAYER_FILING_JOINTLY_FOR_DEPRECIATION_ON_ARMPIT_HAIR)
. 당신은 그렇게하지 않을 것입니다. 당신 AttachForm("B-46")
은 일을했거나 일할 모든 개발자가 "B-46"이 단일 납세자 신고를위한 형식 코드라는 것을 알게 될 것입니다. 양식 코드는 도메인 자체의 일부이므로 절대 변경되지 않으므로 실제로 마법의 숫자가 아닙니다.
따라서 비즈니스 로직에서 상수를 조금만 사용해야합니다. 기본적으로 "매직 넘버"가 실제로 매직 넘버인지 또는 잘 알려진 도메인인지 이해해야합니다. 도메인 인 경우 변경 될 가능성이없는 한 소프트 코딩하지 않습니다.
오류 코드 및 상태 플래그
혹시라도 맞은 가난한 나쁜 놈이 당신에게 말할 수 있듯이, 이것들은 하드 코딩하기에는 결코 괜찮지 않습니다Previous action failed due to error code 46
. 언어가 지원하는 경우 열거 형을 사용해야합니다. 그렇지 않으면 일반적으로 특정 오류 유형에 유효한 값을 지정하는 상수로 가득 찬 전체 파일 / 모듈이 있습니다.
return 42
오류 처리기에서 보지 못하게 하시겠습니까? 변명하지.
아마 몇 가지 시나리오를 생략했지만 그 중 대부분을 다루고 있다고 생각합니다.
그렇습니다. 때로는 하드 코딩하는 것이 좋습니다. 그것에 대해 게으르지 마십시오. 평범한 엉성한 코드보다는 의식적인 결정이어야합니다.
식별자를 숫자에 할당하는 데는 여러 가지 이유가 있습니다.
이것은 우리에게 하드 코딩 리터럴에 대한 기준을 제공합니다. 한 곳이나 상황에서만 발생하며 인식 할 수있는 의미로 불변의 형태로 입력하기 어렵지 않아야합니다. 예를 들어 0을 ARRAY_BEGINNING으로 정의하거나 1을 ARRAY_INCREMENT로 정의 할 필요는 없습니다.
다른 답변에 추가하여. 가능하면 문자열에 상수를 사용하십시오. 물론, 당신은 갖고 싶지 않아
const string server_var="server_var";
하지만 당신은해야합니다
const string MySelectQuery="select * from mytable;";
(실제로 특정 테이블에서 모든 결과를 얻으려는 쿼리가 실제로 있다고 가정하면)
그 외에는 0 (보통) 이외의 숫자에 상수를 사용하십시오. 255의 권한 비트 마스크가 필요한 경우 사용하지 마십시오
const int 8th_bit=255; //or some other obscure naming scheme that equates to 255.
대신에 사용
const int AllowGlobalRead=255;
물론 상수와 함께 열거자를 언제 사용할지 알아야합니다. 위의 경우는 아마도 하나에 잘 맞을 것입니다.
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
하드 코딩 고려 사항에 따라 다릅니다. 하드 코딩 된 모든 항목을 피하려고하면 소프트 코딩 영역 이 생겨서 제작자 만 관리 할 수있는 시스템을 구축하게됩니다 (그리고 이것이 궁극적 인 하드 코드입니다).
많은 것들이 합리적인 프레임 워크로 하드 코딩되어 작동합니다. 즉, C # 응용 프로그램 (static void Main)의 진입 점을 변경할 수 없어야하는 기술적 인 이유는 없지만 어떤 사용자에게도 문제를 일으키지 않는 하드 코딩 (때로는 SO 질문 제외 )
내가 사용하는 경험의 규칙은 전체 시스템의 상태에 영향을 미치지 않고 변경 될 수있는 것과 변경 될 수있는 것은 모두 혼동 가능해야한다는 것입니다.
따라서 IMHO, 절대 변하지 않는 것들 (pi, 중력 상수, 수학 공식의 상수-구의 부피)을 하드 코딩하지 않는 것은 어리석지 않습니다.
또한 어떤 경우 든 프로그래밍이 필요한 시스템에 영향을 미치는 사물이나 프로세스를 하드 코딩하지 않는 것은 바보 같은 일이 아닙니다. 즉, 추가 된 필드에 유지 보수 개발자가 들어가서 작동시킬 스크립트를 작성하십시오. 또한 일부 구성 도구를 만드는 것은 어리 석고 (엔터프라이즈 환경에서는 몇 번 보았습니다) 하드 코딩 된 것은 없지만 IT 부서의 개발자만이 사용할 수 있으며 사용하는 것보다 약간 더 쉽습니다 Visual Studio에서 수행하십시오.
결론적으로, 물건을 하드 코딩해야하는지 여부는 두 변수의 함수입니다.
애플리케이션에 값을 하드 코딩하는 것이 좋은 생각입니까?
값이 사양 (사양의 최종 릴리스에서) 에 지정된 경우 에만 값을 하드 코딩합니다 . 예를 들어 HTTP OK 응답은 항상 (RFC에서 변경되지 않는 한)이므로 ) 상수 :200
public static final int HTTP_OK = 200;
그렇지 않으면 속성 파일에 상수를 저장합니다.
내가 사양을 지정한 이유는 사양의 상수를 변경하려면 변경 관리가 필요하기 때문에 이해 관계자가 변경을 검토하고 승인 / 승인하지 않기 때문입니다. 밤새 일어나지 않으며 승인에 몇 개월 / 년이 걸립니다. 많은 개발자가 사양 (예 : HTTP)을 사용하므로 변경하면 수백만 개의 시스템이 손상된다는 것을 잊지 마십시오.
코드에서 데이터를 추출 할 수 있으면 남은 것이 향상되는 것으로 나타났습니다. 새로운 리팩토링에 주목하고 코드의 전체 섹션을 개선하기 시작합니다.
상수 추출을 위해 노력하고, 어리석은 규칙으로 생각하지 말고, 더 나은 코딩 기회로 생각하는 것이 좋습니다.
가장 큰 장점은 비슷한 상수가 코드 그룹의 유일한 차이점이라는 것을 발견하는 방법입니다. 파일을 배열로 추출하면 일부 파일의 크기를 90 % 줄이며 그 동안 꽤 많은 복사 및 붙여 넣기 버그를 수정하는 데 도움이되었습니다. .
아직 데이터를 추출하지 않는 이점이 하나도 없습니다.
최근에 두 개의 위도 / 경도 쌍 사이의 거리를 올바르게 계산하기 위해 MySQL 함수를 코딩했습니다. 피 타고 루스 만 할 수는 없습니다. 위도가 극쪽으로 갈수록 경도선이 더 가까워 지므로 약간의 털이 많은 삼각대가 있습니다. 요점은 지구의 반경을 나타내는 값을 마일 단위로 하드 코딩할지 여부에 대해 상당히 찢어졌습니다.
사실, 위도 / 경도 선이 달과 훨씬 더 가깝습니다. 그리고 내 기능은 목성의 점 사이의 거리를 크게 과소 평가합니다. 외계인 위치를 입력하는 웹 사이트의 확률이 상당히 낮다고 생각했습니다.
언어가 컴파일되었는지 여부에 따라 다릅니다. 컴파일되지 않은 경우 큰 문제는 아니지만 프로그래머가 아닌 사람에게는 약간 섬세하더라도 소스 코드를 편집하기 만하면됩니다.
컴파일 된 언어로 프로그래밍하는 경우 변수가 변경되면 다시 컴파일해야하므로이 변수를 조정하려면 시간이 많이 걸리기 때문에 이는 좋은 생각이 아닙니다.
변수를 동적으로 변경하기 위해 슬라이더 나 인터페이스를 만들 필요는 없지만 텍스트 파일 만 있으면됩니다.
예를 들어, ogre 프로젝트에서는 항상 ConfigFile 클래스를 사용하여 구성 파일에 쓴 변수를로드합니다.
상수가 (최소한 견해로는) 괜찮은 두 가지 경우 :
다른 것과 관련이없는 상수; 다른 것을 변경하지 않고도 원할 때마다 상수를 변경할 수 있습니다. 예 : 그리드 열의 기본 너비입니다.
"일주일 수"와 같이 절대적으로 불변의 정확하고 명백한 상수. days = weeks * 7
장착 7
상수로하는 것은 DAYS_PER_WEEK
거의 모든 값을 제공하지 않는다.
나는 Jonathan과 완전히 동의하지만 모든 규칙에 예외가 있습니다 ...
"사양의 마법 번호 : 코드의 마법 번호"
기본적으로 스펙에 대한 서술적인 문맥을 얻기 위해 합리적으로 시도한 후에 스펙에 남아있는 매직 넘버는 코드에 그대로 반영되어야한다고 명시되어 있습니다. 만약 마법의 숫자가 코드에 남아 있다면, 그것들을 분리하고 그것들의 원점과 명확하게 연결되도록 모든 노력을 기울여야한다.
데이터베이스에서 매핑 된 값으로 메시지를 채워야하는 몇 가지 인터페이스 계약을 수행했습니다. 대부분의 경우 매핑은 매우 간단하고 Jonathan의 일반 지침에 적합하지만 대상 메시지 구조가 끔찍한 경우가 발생했습니다. 구조에서 전달되어야하는 값의 80 % 이상이 먼 시스템의 사양에 의해 강제 된 상수였습니다. 이것은 메시지 구조가 엄청나다는 사실과 결합하여 그러한 많은 상수를 채워야했습니다. 대부분의 경우 그들은 의미 또는 이유를 제공하지 않았으며, 단지 "M을 여기에 넣다"또는 "4.10.53.10100.889450.4452를 여기에 넣으십시오"라고 말했습니다. 나는 그들 모두 옆에 주석을 넣지 않았으며 결과 코드를 읽을 수 없게 만들었습니다.
즉, 당신이 그것에 대해 생각할 때 ... 명백하게 만드는 것이 거의 전부입니다 ...
지구의 중력 상수의 값을 하드 코딩하고 있다면 아무도 신경 쓰지 않을 것입니다. 프록시 서버의 IP 주소를 하드 코딩하면 문제가 생길 수 있습니다.
대부분 아니요,하지만 하드 코딩 된 값을 복제하기 시작할 때 가장 큰 문제가있을 것입니다. 그것을 복제하지 않으면 (예 : 클래스 구현에서 한 번만 사용하십시오) 상수를 사용하지 않는 것이 좋습니다.