애플리케이션에 값을 하드 코딩하는 것이 좋은 생각입니까? 아니면 변경해야 할 경우 이러한 유형의 값을 동적으로 호출하는 것이 항상 올바른 방법입니까?
설명
에 대한 Wikipedia 기사를 참조하십시오. 답변
예,하지만 명백하게 .
해야 할 일 :
- 상수
- 설명 사용 변수 이름
사용
금지 :
- 매직 넘버 코드 주위에 떠 다니기
댓글
- 더 깔끔한,
diameter = 2 * radius
또는diameter = RADIUS_TO_DIAMETER_FACTOR * radius
? 실제로 매직 넘버가 더 나은 솔루션이 될 수있는 코너 케이스가 있습니다. - 나는 동의 할 수 없습니다 ‘ 저는 프로그래밍을 소설가처럼 생각하는 경향이 있습니다. 코드를 통해 이야기를 전달하고 사람들이 논리를 이해하지 못하면 내 생각으로는 코드를 쓸모 없게 만듭니다. 그 ‘ 이는 명명 규칙이 본질적으로 가독성을위한 이유입니다. 또한 매직 넘버를 사용할 이유가 없습니다. 매직 넘버를 사용하면 ” 이유 방정식에서 벗어나기 어렵게 만듭니다. tand. 예 : ” diameter = 2 * radius ” 두 가지 용도는 무엇입니까? 이 ” 직경 = RADIUS_TO_DIAMETER_FACTOR * 반경 “이 훨씬 더 의미가 있습니다.
- 직경 = 2 * 반경은 고등학교 수학. ” 2 “의 이름을 지정하지 않은 이유는 다른 값을 갖기 위해서는 법칙을 변경해야하기 때문입니다. 물리학이나 수학, 또는 둘 다. (반면에 Pi 또는 Plancks 상수의 이름을 지정하는 것은 간단한 가독성을 위해 좋은 방법입니다.)
- @Joonas : Pfft.
diameter = radius << 1
를 말씀하시는 건가요?diameter = radius << RADIUS_TO_DIAMETER_BITS_TO_SHIFT
일 수도 있습니다. - 일부
diameter = radius.toDiameter()
답변
이 질문에 대해 이상한 점 & 지금까지 아무도 실제로 “하드 코드”또는 더 중요한 대안을 명확하게 정의하려고 시도하지 않았습니다.
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)
를 쓰면 갑자기 모든 것이 훨씬 더 명확 해지고 내부 em에 매직 넘버를 넣어도 괜찮습니다. > 함수 (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)
를 작성하는 것이 정말 정말 부담스럽고 정직하게 무의미 해집니다. 당신은 그쪽으로하지 않을 것입니다 t, 당신은AttachForm("B-46")
로 이동합니다. 왜냐하면 그곳에서 일했거나 일할 모든 개발자는 “B-46″이 단일 납세자의 양식 코드라는 것을 알게 될 것이기 때문입니다. 파일링 blah blah blah-양식 코드는 도메인 자체의 일부이며 절대 변경되지 않으므로 “정말 마법의 숫자가 아닙니다.따라서 비즈니스 로직에서 상수를 아껴 사용해야합니다. 기본적으로 “매직 넘버”가 실제로 매직 넘버인지 아니면 “도메인의 잘 알려진 측면인지 이해해야합니다. 도메인이라면 소프트 코딩하지 않습니다.” 변경 될 가능성이 매우 높습니다.
-
오류 코드 및 상태 플래그
Previous action failed due to error code 46
에 맞은 불쌍한 놈이라면 누구나 알 수 있듯이 하드 코딩 할 수 절대 없습니다. 언어에서 지원하는 경우 열거 형을 사용해야합니다. 그렇지 않으면 일반적으로 특정 오류 유형에 대해 유효한 값을 지정하는 상수로 가득 찬 전체 파일 / 모듈을 갖게됩니다.return 42
오류 처리기에서 capiche? 변명의 여지가 없습니다.
아마도 몇 가지 시나리오를 생략했지만 대부분의 시나리오가 포함 된 것 같습니다.
그래서, 예, 때로는 허용되는 관행입니다. 하드 코딩하는 것입니다. 게으르지 마십시오. 평범하고 엉성한 코드가 아닌 의식적인 결정이어야합니다.
댓글
- 좋은 분석에 감사드립니다! -대부분의 사람들은 ‘ 제가 추가 할 모든 옵션을 생각하지 않습니다. ” 환경 구성 ” -대부분의 데이터는 구성 파일이나 데이터베이스에 넣어야하므로 하드 코딩 된 것이 아니라 피해야한다고 생각합니다. 이는 MVC 또는 MVVM의 주류 인 ” 데이터와 논리를 분리하여 ” 유지하는 원칙을 따릅니다. string TestServerVar = ” foo “; string ProdServerVal = ” bar “;
답변
번호에 식별자를 할당하는 데는 여러 가지 이유가 있습니다.
- 번호가 변경 될 수있는 경우 식별자가 있어야합니다. 9의 모든 인스턴스를 검색하고 8로 변경해야하는지 여부를 고려하는 것보다 NUMBER_OF_PLANETS를 찾는 것이 훨씬 쉽습니다. 소프트웨어를 다른 언어로 사용해야하는 경우 문자열을 변경해야 할 수 있으며 “미리 예측하기 어렵습니다.)
- 숫자는 어떤 식 으로든 입력하기 어렵습니다. pi와 같은 상수의 경우 여러 위치에 다시 입력하는 것보다 하나의 최대 정밀도 정의를 제공하는 것이 더 좋습니다. / li>
- 번호가 다른 위치에있는 경우. 인접한 함수에서 45의 두 가지 용도를 살펴보고 동일한 의미인지 궁금해해서는 안됩니다.
- 의미를 “즉각 인식 할 수없는 경우. 모든 사람이 3.14159265 …가 무엇인지 알고 있다고 가정하는 것이 안전합니다. 이렇게 가정하는 것은 안전하지 않습니다. 모두가 중력 상수 또는 심지어 pi / 2를 인식 할 것입니다. (여기서 “Everybody”는 소프트웨어의 특성에 따라 다릅니다. 시스템 프로그래머는 Unix 권한 비트 등의 8 진수 표현을 알고 있어야합니다. 해군 / 해상 아키텍처 소프트웨어에서 제안 된 선체의 Froude 번호와 속도를 확인합니다. 1.1 이상이 작업해야하는 모든 사람에게 완벽하게 자명한지 확인하십시오.)
- 컨텍스트를 인식 할 수없는 경우 . 누구나 한 시간에 60 분이 있다는 것을 알고 있지만, 수량이 시간 값 또는 비율 값이라는 즉각적인 표시가없는 경우 60을 곱하거나 나누는 것이 불분명 할 수 있습니다. .
이것은 우리에게 하드 코딩 리터럴에 대한 기준을 제공합니다. 리터럴은 변경 불가능해야하며 입력하기 어렵지 않아야하며 한 위치 또는 컨텍스트에서만 발생하며 인식 가능한 의미를 가져야합니다. 예를 들어 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 {state_0 = 0, state_1 = 1, state_2 = 2, .. .} … 웃지 마세요. ‘ 웃지 마세요. ‘ 한 번도 본 적이 있습니다. 젖은 물고기로 그 사람의 머리를 때 리세요!
- @ 물론 ‘
typedef enum {init_state=0, parse_state=1, evaluation_state=2, ... }
- THIS_NAMING_CONVENTION_IS_RECOMMENDED_FOR_CONSTANTS
- 문자열의 경우 ‘ 상수 만 원하지 않습니다. 사용자가 볼 수있는 문자열을 일종의 리소스 파일 (플랫폼에 따라 다름)에 넣어 쉽게 다른 언어로 변경할 수 있습니다.
- 비즈니스 로직 관련을 고수 할 수도 있습니다. 일종의 암호화 또는 난독 화가있는 리소스 파일의 문자열 (예 : SQL 쿼리) 그러면 ” 호기심이 많은 ” 사용자가 논리 (또는 데이터베이스 스키마)를 리버스 엔지니어링하지 못합니다.
답변
하드 코딩 고려 대상에 따라 다릅니다. 하드 코딩 된 모든 것을 피하려고하면 결국 소프트 코딩 영역에 들어가서 제작자 만 관리 할 수있는 시스템을 만듭니다. 궁극의 하드 코드)
많은 것들이 합리적인 프레임 워크에서 하드 코딩되고 작동합니다. 즉, C # 애플리케이션의 진입 점을 변경할 수없는 기술적 이유가 없습니다 (static void Main ), 그러나 어떤 사용자에게도 문제를 일으키지 않는 하드 코딩 (가끔 SO 질문 제외)
내가 사용하는 경험 법칙은 다음과 같습니다. 전체 시스템의 상태에 영향을주지 않고 변경 될 수 있고 변경 될 수있는 모든 것은 구성 할 수 있어야합니다.
따라서 IMHO, 절대 변경되지 않는 것을 하드 코딩하지 않는 것은 어리석은 일입니다 (pi, 중력 상수, 수학적 공식의 상수-구의 부피를 생각하십시오.)
또한 어떤 경우에도 프로그래밍이 필요한 시스템에 영향을 미칠 것 또는 프로세스를 하드 코딩하지 않는 것은 어리석은 일입니다. .e. 사용자가 양식에 동적 필드를 추가 할 수 있도록 허용하는 것은 낭비입니다. 추가 된 필드가 있으면 유지 보수 개발자가 해당 작업을 수행 할 스크립트를 작성해야합니다. 또한 일부 구성 도구를 만드는 것은 어리석은 일입니다 (그리고 엔터프라이즈 환경에서 몇 번 봤습니다). 따라서 하드 코딩 된 도구는 없지만 IT 부서의 개발자 만 사용할 수 있으며 약간 더 쉽습니다. Visual Studio에서 사용하는 것보다 사용하는 것입니다.
그래서 결론적으로 어떤 것이 하드 코딩되어야하는지 여부는 두 가지 변수의 함수입니다.
- 값이 변경됩니다.
- 값 변경이 시스템에 미치는 영향
답변
애플리케이션에 값을 하드 코딩하는 것이 좋은 생각입니까?
I 하드 코딩 값은 만 사양 (사양의 최종 릴리스에서)에 지정 , 예 : HTTP OK 응답은 항상 200
(RFC에서 변경되지 않는 한)이므로 다음과 같은 상수 (일부 코드에서)가 표시됩니다.
public static final int HTTP_OK = 200;
그렇지 않으면 상수를 속성 파일에 저장합니다.
사양을 지정한 이유는 사양의 상수를 변경하려면 변경 관리가 필요하기 때문입니다. 이해 관계자는 변경 사항을 검토하고 승인 / 비 승인합니다. 하룻밤 사이에 발생하지 않으며 승인을받는 데 몇 개월 / 년이 걸립니다. 많은 개발자가 사양 (예 : HTTP)을 사용하므로이를 변경하면 수백만 시스템이 중단된다는 사실을 잊지 마십시오.
답변
- 값이 변경 될 수 있고 실제로 변경 될 수 있다면 관련된 노력이 예상 수익을 초과하지 않는 한 가능할 때마다 소프트 코드를 작성하십시오.
- 일부 값은 불가능 소프트 코딩 됨. (드문) 사례에 대해서는 Jonathan의 지침을 따릅니다.
답변
코드에서 데이터를 추출 할 수있을 때마다 남은 부분이 향상됩니다. 새로운 리팩토링을 발견하고 코드의 전체 섹션을 개선하기 시작합니다.
상수를 추출하는 작업을하는 것이 좋습니다. 어리석은 규칙이라고 생각하지 말고 코드를 작성할 기회로 생각하세요. 더 좋습니다.
가장 큰 장점은 비슷한 상수가 코드 그룹의 유일한 차이점이라는 것을 발견 할 수 있다는 것입니다.이를 배열로 요약하면 일부 파일의 크기를 90 % 줄이고 상당히 수정하는 데 도움이되었습니다. 그 동안 몇 가지 사본 & 붙여 넣기 버그.
데이터를 추출하지 않는 한 가지 장점은 아직 보지 못했습니다.
Answer
저는 최근에 두 개의 위도 / 경도 쌍 사이의 거리를 제대로 계산하기 위해 MySQL 함수를 코딩했습니다. 피 타고 루스 만 할 수는 없습니다. 경도선은 위도가 극쪽으로 증가함에 따라 서로 가까워 지므로 약간의 복잡한 삼각 관계가 있습니다. 요점은 지구 반경을 마일 단위로 나타내는 값을 하드 코딩할지 여부에 대해 상당히 고민했습니다.
사실은 달과 같이 위도 / 위 도선이 훨씬 더 가깝지만 결국 그렇게했습니다. 그리고 내 기능은 목성의 지점 사이의 거리를 과소보고합니다. 내가 구축하고있는 웹 사이트가 외계 위치에 들어갈 확률이 매우 낮다고 생각했습니다.
댓글
- 예, 아마도 요. google.com/moon
답변
언어가 컴파일되었는지 여부에 따라 다릅니다. 컴파일되지 않은 경우 큰 문제가 아닙니다. 프로그래머가 아닌 사람에게는 약간 섬세 할지라도 소스 코드 만 편집하면됩니다.
컴파일 된 언어로 프로그래밍하는 경우 이는 분명히 좋은 생각이 아닙니다. 변수가 변경되면 다시 컴파일해야하므로이 변수를 조정하려면 시간 낭비입니다.
그의 변수를 동적으로 변경하기 위해 슬라이더 나 인터페이스를 만들 필요는 없지만 최소한 텍스트 파일 만 있으면됩니다.
예를 들어 내 오우거 프로젝트에서는 항상 사용하고 있습니다. 구성 파일에 작성한 변수를로드하기위한 ConfigFile 클래스.
Answer
상수가 (적어도 제 생각에는) 괜찮은 두 경우 :
-
다른 것과 관련된 상수; 다른 것을 변경하지 않고도 원할 때마다 이러한 상수를 변경할 수 있습니다. 예 : 그리드 열의 기본 너비.
-
주당 일수와 같이 절대적으로 불변하고 정확하며 명백한 상수입니다.
days = weeks * 7
7
를 상수DAYS_PER_WEEK
로 바꾸면 값이 거의 제공되지 않습니다.
답변
저는 Jonathan과 완전히 동의하지만 모든 규칙에는 예외가 있습니다 …
“사양의 매직 넘버 : 코드의 매직 넘버”
기본적으로 설명 컨텍스트를 얻기위한 합리적인 시도 후에 스펙에 남아있는 매직 넘버는 코드에 그대로 반영되어야합니다. 매직 넘버가 코드에 남아 있다면 그것들을 분리하고 그것들을 원점에 명확하게 연결하기 위해 모든 노력을 기울여야합니다.
매핑 된 값으로 메시지를 채울 필요가있는 몇 가지 인터페이스 계약을 수행했습니다. 데이터베이스에서. 대부분의 경우 매핑은 매우 간단하고 Jonathan의 일반적인 지침에 맞을 것입니다.하지만 대상 메시지 구조가 끔찍한 경우를 만났습니다.구조에서 전달되어야하는 값의 80 % 이상이 먼 시스템의 사양에 의해 강제 된 상수였습니다. 이것은 메시지 구조가 거대하다는 사실과 결합되어 그러한 상수를 많이 채워야했습니다. 대부분의 경우 의미 나 이유를 제공하지 않고 “여기에 M 입력”또는 “여기에 4.10.53.10100.889450.4452 입력”이라고 말했습니다. 나는 결과 코드를 읽을 수 없게 만들었을 모든 항목 옆에 주석을 두려고 시도하지 않았습니다. 그러나 이러한 매직 값이 나타나는 코드 섹션이 적절하게 격리되어 있고 컨테이너 (클래스, 패키지)의 이름이 적절하게 지정되어이를 적용하는 사양을 직접 가리 키도록했습니다.
그것 … 그것은 거의 모든 것을 명백하게 …
답변
당신이 “지구의 중력 상수의 값을 하드 코딩한다면, 아무도”신경 쓰지 않을 것입니다. 프록시 서버의 IP 주소를 하드 코딩하면 “문제가 발생할 수 있습니다.
댓글
- 어스에 더 많은 정밀도가 필요할 수 있습니다. ‘의 중력 상수이므로 여러 번 하드 코딩하면 문제가 발생할 수 있습니다.
- Peter Noone? Herman에서 ‘ s Hermits ?
- 지구의 중력 가속도는 대부분의 위도와 고도에서 9.81m / s ^ 2입니다 (물론 ‘ 석유를 검색하는 경우 다른 행성의 중력 가속도는 다른 숫자이지만, 내가 아는 한 중력 상수는 일정합니다. g가 가변적이라면 변화해야 할 물리학이 많이 있습니다.
답변
대부분 아니오,하지만 당신이 하드 코딩 된 값을 복제하기 시작할 때 가장 많은 문제가 발생합니다. 복제하지 않으면 (예 : 클래스 구현에서 한 번만 사용) 상수를 사용하지 않는 것이 좋습니다.
pi
의 값이 언제 바뀔지 알 수 없습니다 …