태그 보관물: design

design

“소프트 코딩”이란 무엇입니까? 비즈니스 규칙에 변경

에서 이 문서 알렉스 Papadimoulis으로,이 조각을 볼 수있다 :

private void attachSupplementalDocuments()
{
  if (stateCode == "AZ" || stateCode == "TX") {

    //SR008-04X/I are always required in these states
    attachDocument("SR008-04X");
    attachDocument("SR008-04XI");
  }

  if (ledgerAmnt >= 500000) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
  }

  if (coInsuredCount >= 5  && orgStatusCode != "CORP") {
    //Non-CORP orgs with 5 or more co-ins require AUTHCNS-1A
    attachDocument("AUTHCNS-1A");
  }
}

나는이 기사를 정말로 이해하지 못한다.

나는 인용한다 :

모든 비즈니스 규칙 일정이 일부 구성 파일에 저장 한 경우, 생활이 많은 것 [이상 ( 원문 )] 어려운 소프트웨어 유지 보수 모두를위한 하나, 큰 파일을 공유 코드 파일이 많이있을 것를 (또는 그 반대, 아주 작은 구성 파일들); 비즈니스 규칙에 변경 사항을 배치하려면 새 코드가 필요하지 않지만 구성 파일을 수동으로 변경해야합니다. 디버깅이 훨씬 더 어렵습니다.

이는 구성 파일에 “500000”상수 정수 또는 “AUTHCNS-1A”및 기타 문자열 상수를 갖는 것에 대한 인수입니다.

이것이 어떻게 나쁜 습관이 될 수 있습니까?

이 스 니펫에서 “500000”은 숫자가 아닙니다. 예를 들어 다음과 동일하지 않습니다.

int doubleMe(int a) { return a * 2;}

여기서 2는 추상화 할 필요가없는 숫자입니다. 그 사용법은 분명하며 나중에 재사용 할 수있는 것은 아닙니다.

반대로 “500000”은 단순한 숫자가 아닙니다. 기능의 중단 점에 대한 아이디어를 나타내는 중요한 가치입니다. 이 번호는 여러 곳에서 사용할 수 있지만 사용중인 번호는 아닙니다. 그것은 어떤 규칙이 적용되는지, 어떤 규칙이 적용되는지에 대한 한계 / 경계선에 대한 아이디어입니다.

방법도 구성 파일에서 참조하거나하는 #define, const또는 언어는 그 값을 포함하여보다 악화 제공 무엇? 나중에 프로그램이나 다른 프로그래머가 그 경계선을 필요로하므로 소프트웨어가 다른 선택을 수 있습니다. 변경 될 때 두 파일에서 변경 될 것이라는 보장은 없습니다. 그것은 디버깅에 분명히 나쁘다.

또한 내일 정부에서 “5/3/2050부터 AUTHLDG-1A 대신 AUTHLDG-122B를 추가해야합니다”가 필요한 경우이 문자열 상수는 단순한 문자열 상수가 아닙니다. 아이디어를 나타내는 것입니다. 그것은 그 아이디어의 현재 가치 일뿐입니다 ( “원장이 500k 이상인 경우 추가하는 것”).

명확히하겠습니다. 나는 그 기사가 잘못되었다고 말하는 것이 아니다. 나는 그것을 얻지 못한다. 어쩌면 (적어도 내 생각에는) 너무 잘 설명되어 있지 않을 수도 있습니다.

가능한 모든 문자열 리터럴 또는 숫자 값을 상수, 정의 또는 구성 변수로 바꾸는 것이 필요 할뿐만 아니라 지나치게 복잡하지만이 특정 예가이 범주에 속하지 않는 것으로 이해합니다. 나중에 필요하지 않다는 것을 어떻게 알 수 있습니까? 아니면 그 문제에 대해 다른 사람이 있습니까?



답변

저자는 조기 추상화에 대해 경고하고 있습니다.

이 선 if (ledgerAmt > 500000)은 요구 사항이 엄청나게 복잡하지만 정확하고 잘 문서화되어있는 복잡한 대규모 비즈니스 시스템에 대해 기대할 수있는 일종의 비즈니스 규칙처럼 보입니다.

일반적으로 이러한 종류의 요구 사항은 유용하게 재사용 가능한 논리가 아닌 예외적 / 가장 높은 경우입니다. 이러한 요구 사항은 일반적으로 엔지니어가 아닌 비즈니스 분석가 및 주제 전문가가 소유하고 유지 관리합니다.

(이러한 경우 비즈니스 분석가 / 전문가의 요구 사항에 대한 ‘소유권’은 일반적으로 전문가 분야의 개발자가 도메인 전문 지식이 충분하지 않은 경우에 발생하지만 개발자와 도메인 전문가 간의 완벽한 커뮤니케이션 / 협력을 통해 계속 보호 할 수 있습니다. 모호하거나 잘못 작성된 요구 사항.)

요구 사항이 엣지 케이스와 매우 복잡한 로직으로 가득 찬 시스템을 유지 관리 할 때는 일반적으로 해당 로직을 유용하게 추상화하거나보다 유지 관리하기 쉬운 방법이 없습니다. 추상화를 시도하면 쉽게 역효과를 낼 수 있습니다. 시간 낭비뿐만 아니라 유지 관리가 어려운 코드도 만들어집니다.

구성 파일 또는 #define, const 또는 언어가 제공하는 모든 것에서 값을 포함하는 것보다 그것을 어떻게 참조합니까? 나중에 프로그램이나 다른 프로그래머가 그 경계선을 필요로하므로 소프트웨어가 다른 선택을 할 수 있습니다. 변경 될 때 두 파일에서 변경 될 것이라는 보장은 없습니다. 그것은 디버깅에 분명히 나쁘다.

이러한 종류의 코드는 코드 자체가 요구 사항에 일대일로 매핑되어 있다는 사실에 의해 보호되는 경향이 있습니다. 개발자가 때 즉 알고 것을 500000그림은 요구 사항에 두 번 나타납니다, 그 개발자는 또한 코드에 두 번 나타나는 것을 알고있다.

500000요구 사항 문서의 여러 곳에 나타나는 다른 (동일하게) 시나리오를 고려 하지만 주제 전문가는 그 중 하나만 변경하기로 결정합니다. 거기에서 const가치를 바꾸는 누군가 500000가 다른 것을 의미한다는 것을 깨닫지 못할 수도 있는 더 나쁜 위험이 있습니다. 따라서 개발자는 하나를 변경하고 코드에서 찾은 곳에서만 코드를 찾은 다음 무언가를 깨뜨립니다. 그들이 바뀌 었다는 것을 몰랐다.

이 시나리오는 맞춤형 법률 / 재정 소프트웨어 (예 : 보험 견적 논리)에서 많이 발생합니다. 이러한 문서를 작성하는 사람은 엔지니어가 아니며 스펙의 전체 덩어리를 복사하여 붙여 넣기, 몇 단어 / 숫자를 수정하는 데 문제가 없습니다. 대부분을 동일하게 유지합니다.

이러한 시나리오에서 복사 붙여 넣기 요구 사항을 처리하는 가장 좋은 방법은 복사 붙여 넣기 코드를 작성하고 코드가 가능한 모든 요구 사항 (모든 데이터 하드 코딩 포함)과 비슷하게 보이도록하는 것입니다.

이러한 요구 사항의 현실은 일반적으로 오랫동안 복사 + 붙여 넣기 상태를 유지하지 않고 값이 정기적으로 변경되는 경우가 종종 있지만 동시에 변경되지 않으므로 요구 사항을 합리화하거나 추상화하려고합니다. 어떤 식 으로든 요구 사항을 코드로 변환하는 것보다 더 많은 유지 관리 문제가 발생합니다.


답변

이 기사에는 좋은 지적이있다. 구성 파일에 상수를 추출하는 것은 어떻게 나쁜 습관이 될 수 있습니까? 불필요하게 코드를 복잡하게하면 나쁜 습관이 될 수 있습니다. 코드에 직접 값을 갖는 것은 구성 파일에서 값을 읽는 것보다 훨씬 간단하며 작성된 코드를 쉽게 따라갈 수 있습니다.

또한 내일 정부는 “5/3/2050부터 AUTHLDG-1A 대신 AUTHLDG-122B를 추가해야합니다”로갑니다.

그래, 그럼 코드를 바꿔 이 기사의 요점은 구성 파일을 변경하는 것보다 코드를 변경하는 것이 더 복잡하지 않다는 것입니다.

이 기사에서 설명하는 접근 방식은 더 복잡한 논리를 얻는 경우 확장되지 않지만 요점은 판단을 내려야하며 때로는 가장 간단한 솔루션이 가장 좋습니다.

나중에 필요하지 않다는 것을 어떻게 알 수 있습니까? 아니면 그 문제에 대해 다른 사람이 있습니까?

이것이 YAGNI 원칙의 요점입니다. 알려지지 않은 미래를 위해 설계하지 마십시오. 현재에는 완전히 다른 디자인이 될 수 있습니다. 500000 값을 프로그램의 여러 위치에서 사용 하는 경우 물론 상수로 추출해야합니다. 그러나 문제의 코드에서는 그렇지 않습니다.

소프트 코딩은 실제로 우려분리 문제 입니다. 알고 있는 정보 는 핵심 응용 프로그램 논리와 독립적 으로 변경 될 수 있습니다 . 응용 프로그램 논리와는 독립적으로 변경 될 수 있다는 점을 알고 있으므로 다른 환경에 따라 연결 문자열을 구분해야하기 때문에 연결 문자열을 데이터베이스에 하드 코딩하지 마십시오. 웹 앱에서는 비즈니스 로직을 html 템플릿 및 스타일 시트와 분리하려고합니다. 개별적으로 변경 될 수도 있고 다른 사람에 의해 변경 될 수도 있기 때문입니다.

그러나 코드 샘플의 경우 하드 코딩 된 문자열과 숫자는 응용 프로그램 논리의 필수 부분입니다. 제어 외부의 일부 정책 변경으로 인해 하나의 파일 이름이 변경 될 수 있지만 다른 조건에 대해 새 if-branch 검사를 추가해야합니다. 이 경우 파일 이름과 숫자를 추출하면 실제로 응집력이 손상됩니다.


답변

이 기사에서는 ‘엔터프라이즈 규칙 엔진’에 대해 이야기하고 있으며, 이는 아마도 그가 주장하는 것에 대한 더 나은 예일 것입니다.

논리는 구성이 너무 복잡하여 자체 프로그래밍 언어를 포함하는 지점으로 일반화 할 수 있다는 것입니다.

예를 들어, 예제에서 상태 코드 대 문서 맵핑은 구성 파일로 이동 될 수 있습니다. 그러나 복잡한 관계를 표현해야합니다.

<statecode id="AZ">
    <document id="SR008-04X"/>
    <document id="SR008-04XI"/>
</statecode>

원장 금액을 넣을 수도 있습니까?

<statecode id="ALL">
    <document id="AUTHLDG-1A" rule="ledgerAmt >= 50000"/>
</statecode>

곧 새로운 언어로 프로그래밍하고 소스 또는 변경 제어가없는 구성 파일에 해당 코드를 저장하고 있음을 알게되었습니다.

이 기사는 이런 종류의 일이 일반적인 접근 방식 인 2007 년에 작성된 것입니다.

요즘 우리는 의존성 주입 (DI) 문제를 해결할 것입니다 . 즉, ‘하드 코딩 된’

InvoiceRules_America2007 : InvoiceRules

하드 코딩되거나 더 구성 가능한 것으로 대체 할 것입니다.

InvoiceRules_America2008 : InvoiceRules

법률 또는 비즈니스 요구 사항이 변경된 경우


답변

반대로 “500000”은 단순한 숫자가 아닙니다. 기능의 중단 점에 대한 아이디어를 나타내는 중요한 가치입니다. 이 숫자는 여러 곳에서 사용될 수 있지만 사용하고있는 숫자가 아니라 한계 / 경계선에 대한 아이디어로, 어떤 규칙이 적용되고 어떤 규칙이 적용되는지가 결정됩니다.

그리고 그것은 다음과 같이 표현됩니다 (그리고 의견조차도 중복 적이라고 주장 할 수 있습니다).

 if (ledgerAmnt >= 500000) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
  }

이것은 코드가하는 일을 반복합니다.

LEDGER_AMOUNT_REQUIRING_AUTHLDG1A=500000
if (ledgerAmnt >= LEDGER_AMOUNT_REQUIRING_AUTHLDG1A) {
    //Ledger of 500K or more requires AUTHLDG-1A
    attachDocument("AUTHLDG-1A");
}

저자는 500000의 의미가이 규칙과 관련이 있다고 가정합니다. 다른 곳에서 재사용되거나 재사용 될 수있는 값이 아닙니다.

이 이전 소프트 코딩에서 고려할 수있는 유일한 비즈니스 규칙 변경은 AUTHLDG-1A 양식이 필요한 원장 금액의 변경입니다. 다른 비즈니스 규칙을 변경하려면 구성, 문서, 코드 등 더 많은 작업이 필요합니다.

필자의 관점에서 기사의 요점은 때로는 숫자가 단지 숫자라는 것입니다. 코드에서 전달되는 내용 외에 다른 의미로는 사용되지 않을 것이라는 추가 의미는 없습니다. 따라서 하드 코딩 된 값을 피하기 위해 변수 이름에서 코드가 현재 수행중인 작업을 어색하게 요약하는 것은 전혀 불필요한 반복입니다.


답변

다른 답변은 정확하고 신중합니다. 그러나 여기에 짧고 달콤한 대답이 있습니다.

  Rule/value          |      At Runtime, rule/value…
  appears in code:    |   …Is fixed          …Changes
----------------------|------------------------------------
                      |                 |
  Once                |   Hard-code     |   Externalize
                      |                 |   (soft-code)
                      |                 |
                      |------------------------------------
                      |                 |
  More than once      |   Soft-code     |   Externalize
                      |   (internal)    |   (soft-code)
                      |                 |
                      |------------------------------------

규칙과 특수 값이 코드의 한 곳에 나타나고 런타임 중에 변경되지 않으면 질문에 표시된대로 하드 코딩하십시오.

규칙 또는 특수 값이 코드에서 둘 이상의 위치에 나타나고 런타임 중에 변경되지 않으면 소프트 코드입니다. 규칙에 대한 소프트 코딩으로 특정 클래스 / 방법을 정의하거나 빌더 패턴을 사용할 수 있습니다 . 값의 경우 소프트 코딩은 코드 전체에서 사용되는 단일 상수 또는 열거 형을 정의하는 것을 의미 할 수 있습니다.

런타임 동안 규칙 또는 특수 값이 변경 될 수 있으면이를 외부화해야합니다. 일반적으로 데이터베이스의 값을 업데이트하여 수행됩니다. 또는 사용자가 데이터를 입력하여 메모리의 값을 수동으로 업데이트하십시오. 또한 파일 수정 날짜-시간 변경을 위해 반복적으로 스캔되는 텍스트 파일 (XML, JSON, 일반 텍스트 등)에 값을 저장하여 수행됩니다.


답변

이것은 우리가 사용하는 경우에 우리가 가을 함정 장난감 문제를 다음에만 포즈 strawman의 우리가 실제 문제를 설명하려고 할 때, 솔루션을.

주어진 예에서, 주어진 값이 인라인 값으로 하드 코딩되거나 const로 정의되는지의 차이는 없습니다.

예제를 유지 관리 및 코딩 공포로 만드는 것은 주변 코드입니다. 이 경우 없습니다 에는 주변 코드는 다음 코드 조각은 적어도 일정 리팩토링의 환경에서, 괜찮습니다. 리팩토링이 발생하지 않는 환경에서, 해당 코드의 관리자는 이미 명백해지기 때문에 이미 죽었습니다.

주변에 코드가 있으면 나쁜 일이 분명히 발생합니다.

첫 번째 나쁜 점은 50000 값이 일부 주에서 세율이 변하는 원장 금액과 같은 다른 값에 사용된다는 것입니다. 그런 다음 변경이 발생하면 관리자는 알 수 없습니다. 코드에서 50000의 두 인스턴스 (동일한 50k를 의미하는지 또는 전혀 관련이없는 50ks)를 의미합니다. 누군가가 상수를 사용하는 경우 49999 및 50001도 검색해야합니까? 이것은 별도의 서비스의 구성 파일에 변수를 넣는 호출이 아니지만 인라인 하드 코딩도 잘못되었습니다. 대신, 사용되는 클래스 나 파일 내에서 정의되고 범위가 지정된 상수 여야합니다. 50k의 두 인스턴스가 동일한 상수를 사용하는 경우 동일한 입법 제한을 나타냅니다. 그렇지 않다면 아마 그렇지 않을 것입니다. 어느 쪽이든, 그들은 이름을 가질 것입니다.

파일 이름은 기본 파일 이름을 경로 또는 확장자없이 문자열로 허용하는 attachDocument () 함수에 전달됩니다. 파일 이름은 기본적으로 일부 파일 시스템 또는 데이터베이스에 대한 외래 키이거나 attachDocument ()가 파일을 가져 오는 곳입니다. 그러나 문자열은 이것에 대해 아무 것도 말하지 않습니다. 몇 개의 파일이 있습니까? 어떤 유형의 파일입니까? 새로운 시장에 진입 할 때이 기능을 업데이트해야하는지 어떻게 알 수 있습니까? 어떤 유형의 물건을 붙일 수 있습니까? 관리자는 완전히 어둠 속에 남겨져 있으며, 코드에 여러 번 나타날 수있는 문자열 일뿐입니다. 한 곳에서 “SR008-04X”는 치트 코드입니다. 또 다른 방법으로, 4 개의 SR008 부스터 로켓을 주문하라는 명령입니다. 여기 요 sa 파일 이름? 이것들이 관련이 있습니까? 누군가 “CLIENT”라는 다른 파일을 언급하기 위해 해당 기능을 변경했습니다. 그런 다음 유지 관리에 문제가있는 사용자는 “CLIENT”파일의 이름을 “CUSTOMER”로 바꿔야한다는 메시지를 받았습니다. 그러나 문자열 “CLIENT”는 코드에서 937 번 나타납니다. 어디서부터 시작합니까?

장난감 문제는 값이 모두 특이하고 합리적으로 코드에서 고유 보장 할 수 있다는 것입니다. “1”또는 “10”이 아니라 “50,000”입니다. “클라이언트”또는 “보고서”가 아니라 “SR008-04X”입니다.

strawman는 impenetrably 불투명 상수의 문제를 해결하는 유일한 방법은 어떤 관련이없는 서비스의 config 파일에 그들을 하이브하는 것입니다.

이 두 가지 오류를 함께 사용하면 모든 주장이 사실임을 입증 할 수 있습니다.


답변

여기에는 몇 가지 문제가 있습니다.

한 가지 문제는 모든 규칙을 프로그램 외부에서 쉽게 구성 할 수 있도록 규칙 엔진을 구축해야한다는 것입니다. 이와 비슷한 경우의 대답은 가장 자주 없습니다. 규칙은 예측하기 어려운 이상한 방식으로 변경되므로 변경이있을 때마다 규칙 엔진을 확장해야합니다.

또 다른 문제는 버전 관리에서 이러한 규칙과 변경 사항을 처리하는 방법입니다. 여기서 가장 좋은 해결책은 규칙을 각 규칙의 클래스로 나누는 것입니다.

이를 통해 각 규칙마다 고유 한 유효성을 유지하고, 일부 규칙은 매년 변경되며, 허가가 있거나 송장이 발행 될 때 변경되는 일부 변경 사항이 있습니다. 적용 할 버전 확인이 포함 된 규칙 자체입니다.

또한 상수는 개인이므로 코드의 다른 곳에서는 잘못 사용할 수 없습니다.

그런 다음 모든 규칙 목록을 작성하고 목록을 적용하십시오.

추가 문제는 상수를 처리하는 방법입니다. 500000은 눈에 띄지 않을 수 있지만 올바르게 변환되도록 매우주의해야합니다. 부동 소수점 산술을 적용하면 500,000.00001로 변환되어 500,000.00000과의 비교에 실패 할 수 있습니다. 또는 더 나쁜 500000은 항상 의도 한대로 작동하지만 변환시 565000이 실패합니다. 컴파일러가 추측하는 것이 아니라 명시 적으로 변환해야합니다. 종종 사용하기 전에 BigInteger 또는 BigDecimal로 변환하여 수행됩니다.