모범 사례와 중복 조건 검사가 있습니까?


16

나는 지난 3 년간 소프트웨어를 개발해 왔지만 최근에 내가 좋은 관행에 대해 무지한 것으로 깨어났다. 이로 인해 Clean Code 라는 책을 읽게 되었으므로 인생을 더 좋게 만들 수는 있지만 프로그램 작성을위한 최선의 접근법에 대한 통찰력을 얻는 데 어려움을 겪고 있습니다.

나는 파이썬 프로그램을 가지고 있는데 ...

  1. argparse required=True를 사용하여 두 파일 이름 인 두 개의 인수를 적용하십시오. 첫 번째는 입력 파일 이름이고 두 번째는 출력 파일 이름입니다.
  2. readFromInputFile입력 파일 이름이 입력되었는지 먼저 확인 하는 기능 이 있습니다.
  3. writeToOutputFile먼저 출력 파일 이름이 입력되었는지 확인 하는 기능 이 있습니다

내 프로그램은 크기가 작아서 # 2와 # 3의 검사가 중복되어 제거되어야하므로 두 기능을 불필요한 if조건 에서 자유롭게 할 수 있다고 믿습니다 . 그러나 나는 또한 "더블 체크는 괜찮다"고 믿고 파싱이 발생하지 않는 다른 위치에서 함수를 호출 할 수있는 프로그램에서 올바른 솔루션 일 수 있습니다.

(또한 읽기 또는 쓰기가 실패하면 try except각 함수에 적절한 오류 메시지가 표시됩니다.)

내 질문은 : 모든 중복 상태 확인을 피하는 것이 가장 좋습니까? 프로그램의 논리가 너무 단단하여 점검이 한 번만 이루어져야합니까? 이 또는 그 반대를 설명하는 좋은 예가 있습니까?

편집 : 답변 주셔서 감사합니다! 나는 각각에서 무언가를 배웠다. 너무 많은 관점을 살펴보면이 문제에 접근하고 내 요구 사항에 따라 솔루션을 결정하는 방법을 훨씬 더 잘 이해할 수 있습니다. 감사합니다!


여기에 질문을 많이 일반화 된 버전입니다 : softwareengineering.stackexchange.com/questions/19549/... . 초점이 상당히 커서 복제본이라고 말하지는 않지만 도움이 될 수 있습니다.
Doc Brown

답변:


15

당신이 요구하는 것을 "견고성"이라고하며, 옳고 그른 대답은 없습니다. 프로그램의 규모와 복잡성, 프로그램에 참여하는 사람의 수 및 실패 감지의 중요성에 따라 다릅니다.

소규모 프로그램에서는 혼자서 작성하는 것만으로도 견고성은 일반적으로 팀이 작성한 여러 구성 요소로 구성된 복잡한 프로그램을 작성할 때보 다 훨씬 적은 관심사입니다. 이러한 시스템에서는 공개 API 형태의 구성 요소 사이에 경계가 있으며 각 경계에서 "프로그램의 논리가 너무 견고하여 검사가 중복되지 않더라도 입력 매개 변수의 유효성을 검증하는 것이 좋습니다. ". 따라서 버그를 훨씬 쉽게 감지하고 디버깅 시간을 더 작게 유지할 수 있습니다.

귀하의 경우, 프로그램에 대해 어떤 종류의 수명주기를 기대할 것인지 스스로 결정해야합니다. 수년에 걸쳐 사용 및 유지 될 것으로 예상되는 프로그램입니까? 그런 다음 중복 검사를 추가하는 것이 좋습니다. 나중에 코드를 리팩터링하지 않고 함수 readwrite기능을 다른 컨텍스트에서 사용할 수 없기 때문입니다 .

아니면 학습이나 재미있는 목적을위한 작은 프로그램입니까? 그런 다음 이중 점검은 필요하지 않습니다.

"Clean Code"의 맥락에서, 이중 점검이 DRY 원칙을 위반하는지 여부를 물을 수 있습니다. 실제로, 때로는 최소한 어느 정도는 그렇지 않습니다. 입력 유효성 검사는 프로그램의 비즈니스 논리의 일부로 해석 될 수 있으며, 두 곳에서이를 수행하면 DRY 위반으로 인한 일반적인 유지 관리 문제가 발생할 수 있습니다. 견고성 대 DRY는 종종 상충 관계입니다. 견고성에는 코드의 중복성이 필요하지만 DRY는 중복성을 최소화하려고합니다. 또한 프로그램의 복잡성이 증가함에 따라 유효성 검사에서 DRY가되는 것보다 견고성이 더욱 중요 해지고 있습니다.

마지막으로 귀하의 경우에 의미가 무엇인지 예를 들어 보겠습니다. 요구 사항이 다음과 같이 변경되었다고 가정합니다.

  • 프로그램은 또한 하나의 인수, 입력 파일 이름과 함께 작동해야합니다. 출력 파일 이름이 없으면 접미사를 대체하여 입력 파일 이름에서 자동으로 구성됩니다.

그러면 이중 유효성 검사를 두 곳에서 변경해야 할 가능성이 있습니까? 아마도 그러한 요구 사항은 호출 할 때 하나의 변경으로 이어지지 argparse만 변경되지는 않습니다 writeToOutputFile. 해당 함수에는 여전히 파일 이름이 필요합니다. 따라서 귀하의 경우 입력 유효성 검사를 두 번 수행하여 투표합니다. 두 곳을 변경해야하기 때문에 유지 보수 문제가 발생할 위험은 IMHO가 너무 적은 검사로 인한 마스크 오류로 인해 유지 보수 문제가 발생할 위험보다 훨씬 낮습니다.


"... 공용 API 형태의 구성 요소 간 경계 ..." 따라서 필요한 것은 수업입니다. 일관된 비즈니스 도메인 클래스. 나는이 OP에서 "단순하므로 클래스를 필요로하지 않는다"는 유비쿼터스 원리가 작동하고 있다고 추론하고있다. "기본 객체"를 감싸는 간단한 클래스가있을 수 있습니다. "파일에는 이름이 있어야합니다"와 같은 비즈니스 규칙이 적용되어 기존 코드를 건조시킬뿐 아니라 나중에이를 DRY로 유지합니다.
radarbob

@ radarbob : 내가 쓴 것은 OOP 또는 클래스 형태의 구성 요소로 제한되지 않습니다. 이것은 객체 지향 여부에 관계없이 공개 API를 사용하는 임의의 라이브러리에도 적용됩니다.
Doc Brown

5

중복은 죄가 아닙니다. 불필요한 중복성입니다.

  1. 만약 readFromInputFile()하고 writeToOutputFile()있는 공공 기능 (파이썬은 이름이 두 개의 밑줄로 시작하지 않았기 때문에 그들이 명명 규칙에 의해) 다음 기능은 언젠가 모두 argparse 피할 사람에 의해 사용될 수 있습니다. 즉, 인수를 생략하면 사용자 정의 argparse 오류 메시지가 표시되지 않습니다.

  2. 경우 readFromInputFile()writeToOutputFile()매개 변수에 대한 자신을 확인, 다시 파일 이름에 대한 필요성을 설명하는 사용자 지정 오류 메시지를 표시 할 수.

  3. 경우 readFromInputFile()writeToOutputFile()스스로 매개 변수를 확인하지 않는, 어떤 사용자 지정 오류 메시지가 표시되지 않습니다. 사용자는 결과 예외를 스스로 파악해야합니다.

모두 3으로 내려갑니다. argparse를 피하고 이러한 메시지를 실제로 사용하여 오류 메시지를 생성하는 코드를 작성하십시오. 이 함수들을 전혀 보지 않고 사용하기에 충분한 이해를 제공하기 위해 이름을 신뢰한다고 상상해보십시오. 그것이 당신이 아는 전부일 때 예외에 의해 혼동 될 수있는 방법이 있습니까? 사용자 정의 된 오류 메시지가 필요합니까?

이러한 기능의 내부를 기억하는 두뇌 부분을 끄는 것은 어렵습니다. 너무 많은 사람들이 사용되는 코드 전에 using-code를 작성하는 것이 좋습니다. 그렇게하면 외부에서 어떤 것이 보이는지 이미 알고있는 문제가 발생합니다. TDD를 수행 할 필요는 없지만 TDD를 수행하는 경우 먼저 외부에서 들어 오게됩니다.


4

당신이 당신의 방법을 만들되는 정도 독립형재 - 사용 가능한이 좋은 것입니다. 즉, 메소드는 수용하는 것을 용서해야하고 잘 정의 된 출력을 가져야합니다 (반환되는 정확한 것). 그것은 또한 그들이 전달 된 모든 것을 정상적으로 처리 할 수 ​​있어야 하고 입력, 품질, 타이밍 등의 특성에 대해 어떤 가정도하지 않아야한다는 것을 의미합니다 .

프로그래머가 전달 된 내용에 대한 가정을 작성하는 방법을 작성하는 습관을 갖고 있다면 "이것이 깨지면 걱정할 것이 더 크다"또는 "파라미터 X는 Y 값을 가질 수 없습니다. 코드는 그것을 막습니다.”그러면 갑자기 독립된 분리 된 구성 요소가 더 이상 없습니다. 구성 요소는 기본적으로 더 넓은 시스템에 따라 다릅니다. 이것은 일종의 미묘한 밀접한 결합이며 시스템 복잡성이 증가함에 따라 총 소유 비용을 기하 급수적으로 증가시킵니다.

이는 동일한 정보를 두 번 이상 확인하고 있음을 의미 할 수 있습니다. 그러나 이것은 괜찮습니다. 각 구성 요소는 자체 방식으로 자체 유효성 검사 담당합니다 . 유효성 검사는 분리 된 독립 구성 요소에 의한 것이며, 한 가지의 유효성 검사에 대한 변경 사항이 반드시 다른 요소에 정확하게 복제 될 필요는 없기 때문에 이것은 DRY 위반이 아닙니다. 여기에는 중복성이 없습니다. X는 자체 입력에 대한 입력을 확인하고 일부를 Y에 전달할 책임이 있습니다. Y는 필요에 따라 자체 입력을 확인해야 할 책임이 있습니다 .


1

함수가 있다고 가정하십시오 (C)

void readInputFile (const char* path);

그리고 경로에 대한 문서를 찾을 수 없습니다. 그런 다음 구현을 살펴보면

void readInputFile (const char* path)
{
    assert (path != NULL && strlen (path) > 0);

이것은 함수에 대한 입력을 테스트 할뿐만 아니라 함수의 사용자에게 경로가 널 (null)이거나 빈 문자열이 될 수 없음을 알려줍니다.


0

일반적으로 이중 확인이 항상 좋은 것은 아닙니다 . 문제가 의존하는 특정한 경우 에는 항상 질문의 많은 측면이 있습니다. 귀하의 경우 :

  • 프로그램이 얼마나 큽니까? 크기가 작을수록 발신자가 옳은 일을하는 것이 더 분명합니다. 프로그램이 커지면 각 루틴의 전제 조건과 사후 조건을 정확하게 지정하는 것이 더 중요해집니다.
  • 인수는 이미 argparse모듈 에 의해 점검됩니다 . 라이브러리를 사용한 다음 직접 작업하는 것은 좋지 않은 생각입니다. 그렇다면 왜 도서관을 사용합니까?
  • 호출자가 인수를 확인하지 않는 상황에서 메소드가 재사용 될 가능성은 얼마나됩니까? 가능성이 높을수록 인수의 유효성을 검사하는 것이 더 중요합니다.
  • 인수 누락 되면 어떻게됩니까 ? 입력 파일을 찾지 못하면 아마 처리가 중지 될 것입니다. 아마도 수정하기 쉬운 명백한 실패 모드 일 것입니다. 교활한 종류의 오류는 프로그램이 제대로 작동하고 사용자가 눈치 채지 않고 잘못된 결과 생성하는 오류 입니다.

0

이중 점검은 거의 사용되지 않는 곳에 있습니다. 따라서 이러한 검사는 단순히 프로그램을 더욱 강력하게 만듭니다.

너무 많은 수표는 아프지 않을 것이고 너무 적은 수의 것입니다.

그러나 자주 반복되는 루프 내부를 검사하는 경우 검사 자체가 대부분 검사 후에 수행되는 것과 비교하여 비용이 많이 들지 않더라도 중복 제거를 고려해야합니다.


그리고 이미 가지고 있기 때문에 루프 또는 무언가가 아닌 한 제거 노력을 기울일 가치가 없습니다.
StarWeaver

0

아마도 당신의 관점을 바꿀 수있을 것입니다 :

무언가 잘못되면 결과는 어떻습니까? 응용 프로그램 / 사용자에게 해를 끼치나요?

물론 수표가 많든 적든 좋든 나쁘 든 항상 논쟁의 여지가 있습니다. 그리고 실제 소프트웨어를 다루기 때문에 실제 결과가 있습니다.

당신이주는 맥락에서 :

  • 하나의 입력 파일 A
  • 하나의 출력 파일 B

나는 당신이 A 에서 B로 변환하고 있다고 가정합니다 . 경우 와 B가 작고 변형이 작고, 그 결과는 무엇인가?

1) 읽을 위치를 지정 하지 않았습니다 . 결과는 아무것도 아닙니다 . 실행 시간이 예상보다 짧습니다. 당신은 결과를 보거나 더 잘합니다 : 누락 된 결과를 찾으십시오. 잘못된 방법으로 명령을 호출했는지 확인하십시오. 다시 시작하십시오. 다시 괜찮습니다.

2) 출력 파일을 지정하지 않았습니다. 다른 시나리오가 발생합니다.

a) 입력을 한 번에 읽습니다. 변환이 시작되고 결과가 기록되어야하지만 대신 오류가 발생합니다. 시간에 따라 사용자는 기다려야합니다 (처리 될 데이터의 양에 따라 다름). 이는 성 가실 수 있습니다.

b) 입력을 단계별로 읽습니다. 그런 다음 (1)과 같이 쓰기 프로세스가 즉시 종료되고 사용자는 다시 시작합니다.

상황에 따라 실수 확인정상 으로 표시 될 수 있습니다 . 그것은 전적으로 당신의 유스 케이스와 당신의 의도에 달려 있습니다.

또한 편집증을 피하고 너무 많은 재확인을하지 않아야합니다.


0

테스트가 중복되지 않는다고 주장합니다.

  • 입력 매개 변수로 파일 이름이 필요한 두 개의 공용 함수가 있습니다. 해당 매개 변수의 유효성을 검사하는 것이 적절합니다. 기능은 기능이 필요한 모든 프로그램에서 사용될 수 있습니다.
  • 파일 이름이어야하는 두 개의 인수가 필요한 프로그램이 있습니다. 기능을 사용합니다. 프로그램이 매개 변수를 점검하는 것이 적절합니다.

파일 이름을 두 번 확인하는 동안 다른 목적으로 확인하고 있습니다. 기능에 대한 매개 변수를 신뢰할 수있는 작은 프로그램에서 기능 점검이 중복 된 것으로 간주 될 수 있습니다.

보다 강력한 솔루션에는 하나 또는 두 개의 파일 이름 유효성 검사기가 있습니다.

  • 입력 파일의 경우 매개 변수가 읽을 수있는 파일을 지정했는지 확인할 수 있습니다.
  • 출력 파일의 경우, 매개 변수가 쓰기 가능 파일이거나 작성하여 쓸 수있는 유효한 파일 이름인지 확인할 수 있습니다.

작업을 수행 할 때 두 가지 규칙을 사용합니다.

  • 가능한 빨리하십시오. 이것은 항상 필요한 것들에 효과적입니다. 이 프로그램의 관점에서 이것은 argv 값을 확인하는 것이며 프로그램 논리의 후속 유효성 검사는 중복됩니다. 함수가 라이브러리로 이동하면 라이브러리가 모든 호출자가 매개 변수의 유효성을 검증했음을 신뢰할 수 없으므로 더 이상 중복되지 않습니다.
  • 가능한 한 늦게하십시오. 이것은 거의 필요하지 않은 것들에 매우 효과적입니다. 이 프로그램의 관점에서 이것은 기능 매개 변수를 점검하는 것입니다.

0

검사가 중복됩니다. 이 문제를 해결하려면 readFromInputFile 및 writeToOutputFile을 제거하고 readFromStream 및 writeToStream으로 바꾸어야합니다.

코드가 파일 스트림을받는 지점에서 유효한 파일이 유효한 파일에 연결되어 있거나 스트림에 연결할 수있는 다른 항목이 있다는 것을 알고 있습니다. 중복 검사를 피할 수 있습니다.

그런 다음 계속해서 어딘가에서 스트림을 열어야합니다. 예, 그러나 내부적으로 인수 파싱 방법에서 발생합니다. 파일 이름이 필요한지 확인하기위한 두 가지 검사가 있습니다. 다른 하나는 파일 이름이 가리키는 파일이 지정된 컨텍스트에서 유효한 파일인지 확인하는 것입니다 (예 : 입력 파일이 존재하고 출력 디렉토리를 쓸 수 있음). 이것들은 다른 유형의 검사이므로 중복되지 않으며 핵심 응용 프로그램이 아닌 인수 구문 분석 방법 (응용 프로그램 경계) 내에서 발생합니다.

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