TDD가 도움이되지 않을 때 코드에서 논리적 실수를 피하는 방법은 무엇입니까?


67

나는 최근에 사람에게 친숙한 방식으로 사건이 얼마나 오래된지를 나타내는 작은 코드를 작성하고있었습니다. 예를 들어 이벤트가“3 주 전”또는“한 달 전”또는“어제”에 발생했음을 나타낼 수 있습니다.

요구 사항은 비교적 명확했으며 테스트 중심 개발의 경우에는 완벽했습니다. 테스트를 하나씩 작성하고 각 테스트를 통과하는 코드를 구현했으며 모든 것이 완벽하게 작동하는 것처럼 보였습니다. 프로덕션에 버그가 나타날 때까지.

관련 코드는 다음과 같습니다.

now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
    return "Today"

yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
    return "Yesterday"

delta = (now - event_date).days

if delta < 7:
    return _number_to_text(delta) + " days ago"

if delta < 30:
    weeks = math.floor(delta / 7)
    if weeks == 1:
        return "A week ago"

    return _number_to_text(weeks) + " weeks ago"

if delta < 365:
    ... # Handle months and years in similar manner.

테스트는 오늘, 어제, 4 일 전, 2 주 전, 1 주일 전 등의 이벤트가 발생했는지 확인하고 그에 따라 코드가 작성되었습니다.

내가 놓친 것은 어제 하루 전에 이벤트가 발생할 수 있다는 것입니다. 예를 들어, 24 시간 전에 발생한 이벤트는 하루 전에 있었을 것입니다. 무언가이지만 delta정수는 정수이므로 하나 일뿐입니다. 이 경우 응용 프로그램은“일일 전”을 표시하는데 이는 코드에서 예상치 못하고 처리되지 않은 것입니다. 다음을 추가하여 수정할 수 있습니다.

if delta == 1:
    return "A day ago"

를 계산 한 직후 delta.

버그의 유일한 부정적인 결과는이 사건이 어떻게 발생할 수 있는지 궁금해하고 30 분 동안 낭비하고 코드에서 UTC를 균일하게 사용하더라도 시간대와 관련이 있다고 생각하지만 그 존재로 인해 어려움을 겪고 있습니다. 다음을 나타냅니다.

  • 간단한 소스 코드에서도 논리적 실수를 저지르는 것은 매우 쉽습니다.
  • 테스트 주도 개발은 도움이되지 못했습니다.

또한 그러한 버그를 피할 수있는 방법을 알 수 없다는 것이 걱정입니다. 코드를 작성하기 전에 더 많은 것을 생각하는 것 외에도 내가 생각할 수있는 유일한 방법은 내가 결코 일어나지 않을 것이라고 생각하는 경우에 대해 많은 주장을 추가하고 (어제 전은 어제라고 생각한 것처럼) 매초마다 반복하는 것입니다. 지난 10 년 동안 어설 션 위반이 있는지 확인했습니다. 너무 복잡해 보입니다.

처음에이 버그를 만들지 않으려면 어떻게해야합니까?


38
테스트 케이스를 가지고 있습니까? 그것은 당신이 나중에 그것을 발견 한 것처럼 보이고 TDD와 맞물립니다.
OUurous

63
내가 테스트 주도 개발의 팬이 아닌 이유를 방금 경험했습니다. 제 경험상 프로덕션에서 발견 된 대부분의 버그는 아무도 생각하지 못한 시나리오입니다. 테스트 중심 개발 및 단위 테스트는 이것에 대해 아무 것도하지 않습니다. (단위 테스트는 향후 편집을 통해 도입 된 버그를 감지하는 데 가치가 있습니다.)
Loren Pechtel

102
"TDD를 포함한 은색 총알은 없습니다." 완벽한 코드를 생성하기 위해 로봇으로 따를 수있는 프로세스, 규칙 집합, 알고리즘이 없습니다. 있다면 전체 프로세스를 자동화하고 완료 할 수 있습니다.
jpmc26

43
축하합니다, 어떤 테스트도 버그가 없음을 증명할 수 없다는 오래된 지혜를 재발견했습니다. 그러나 가능한 입력 도메인을 더 잘 커버 할 수있는 기술을 찾고 있다면 도메인, 에지 사례 및 해당 도메인의 등가 클래스를 철저히 분석해야합니다. TDD라는 용어가 발명되기 오래 전에 잘 알려진 모든 오래된 기술.
Doc Brown

80
나는 울퉁불퉁하지 않으려 고 노력하지만 귀하의 질문은 "내가 생각하지 않은 것을 어떻게 생각합니까?"로 표현 될 수 있습니다. 그것이 TDD와 어떤 관련이 있는지 확실하지 않습니다.
자레드 스미스

답변:


57

이는 일반적으로 빨강 / 녹색 / 리 팩터 의 리 팩터 단계 에서 발견되는 종류의 오류 입니다. 그 단계를 잊지 마십시오! 다음과 같은 리팩터링을 고려하십시오 (예상치 않음).

def pluralize(num, unit):
    if num == 1:
        return unit
    else:
        return unit + "s"

def convert_to_unit(delta, unit):
    factor = 1
    if unit == "week":
        factor = 7 
    elif unit == "month":
        factor = 30
    elif unit == "year":
        factor = 365
    return delta // factor

def best_unit(delta):
    if delta < 7:
        return "day"
    elif delta < 30:
        return "week"
    elif delta < 365:
        return "month"
    else:
        return "year"

def human_friendly(event_date):
    date = event_date.date()
    today = now.date()
    yesterday = today - datetime.timedelta(1)
    if date == today:
        return "Today"
    elif date == yesterday:
        return "Yesterday"
    else:
        delta = (now - event_date).days
        unit = best_unit(delta)
        converted = convert_to_unit(delta, unit)
        pluralized = pluralize(converted, unit)
        return "{} {} ago".format(converted, pluralized)

여기에서는 훨씬 더 응집력이 높고 독립적으로 테스트하기 쉬운 3 개의 함수를 낮은 수준의 추상화로 만들었습니다. 원하는 시간 범위를 생략하면 간단한 도우미 기능에서 아픈 엄지 손가락처럼 튀어 나옵니다. 또한 중복을 제거하여 오류 가능성을 줄입니다. 깨진 케이스를 구현 하려면 실제로 코드 를 추가 해야합니다 .

이와 같이 리팩토링 된 형식을 볼 때 다른 미묘한 테스트 사례도 더 쉽게 떠 오릅니다. 예를 들어, 부정적인 best_unit경우 어떻게해야 합니까 delta?

다시 말해 리팩토링은 예쁘게 만들기위한 것이 아닙니다. 인간이 컴파일러가 할 수없는 오류를 쉽게 발견 할 수 있습니다.


12
다음 단계는 국제화 pluralize하는 것이며 영어 단어의 하위 집합에 대해서만 작업하는 것이 책임입니다.
중복 제거기

@Deduplicator는 확실하지만 대상 언어 / 문화에 따라 일부 테이블 / 리소스 파일에서 형식 문자열을 가져 오기 위해 어떤 종류의 키만 사용하여 키 pluralize를 작성 num하고 벗어날 수 있습니다 unit. 또는 다른 단위가 필요하기 때문에 논리를 완전히 다시 작성해야 할 수도 있습니다. ;-)
Hulk

4
이 리팩토링에도 문제가 남아 있습니다. 즉, "어제"는 아침의 매우 바쁜 시간 (12:01 AM 직후)에는 의미가 없습니다. 인간 친화적으로, 오후 11시 59 분에 발생한 일이 시계가 자정을 지날 때 갑자기 "오늘"에서 "어제"로 바뀌지 않습니다. 대신 "1 분 전"에서 "2 분 전"으로 변경됩니다. "오늘"은 몇 분 전에 일어난 일로 인해 너무 거칠고 "어제"는 밤 올빼미에게 문제가 있습니다.
David Hammen

@DavidHammen 이것은 유용성 문제이며 필요한 정도에 따라 다릅니다. 적어도 한 시간까지 알고 싶다면 "어제"가 좋지 않다고 생각합니다. "24 시간 전"은 훨씬 명확하며 시간을 강조하기 위해 일반적으로 사용되는 인간 표현입니다. "인간 친화적"이 되려고 노력하는 컴퓨터는 거의 항상이 잘못을 저지르고 너무 어색한 "어제"로 지나치게 일반화합니다. 그러나이 사실을 알기 위해서는 사용자를 인터뷰하여 그들이 어떻게 생각하는지 확인해야합니다. 어떤 경우에는 정확한 날짜와 시간을 원하므로 "어제"는 항상 틀립니다.
Brandin

149

테스트 주도 개발은 도움이되지 못했습니다.

도움이 된 것 같습니다. "하루 전"시나리오에 대한 테스트를받지 않은 것입니다. 이 사례가 발견 된 후 테스트를 추가했을 것입니다. 이것은 여전히 ​​TDD입니다. 버그가 발견되면 버그를 감지하기 위해 단위 테스트를 작성한 다음 수정하십시오.

행동 테스트를 작성하는 것을 잊어 버린 경우 TDD는 도움이되지 않습니다. 테스트 작성을 잊었으므로 구현을 작성하지 마십시오.


2
개발자가 tdd를 사용하지 않았다면 다른 사례를 놓칠 가능성이 훨씬 높았습니다.
Caleb

75
그리고 그 위에 버그를 고칠 때 시간이 얼마나 절약되는지 생각해보십시오. 기존 테스트를 시행함으로써 변경 사항이 기존 동작을 중단하지 않는다는 것을 즉시 알 수있었습니다. 그리고 이후에 광범위한 수동 테스트를 수행하지 않고도 새로운 테스트 사례를 추가하고 리팩터링 할 수있었습니다.
Caleb

15
TDD는 작성된 테스트만큼 우수합니다.
Mindwin

또 다른 관찰 :이 경우에 대한 테스트를 추가하면 디자인 datetime.utcnow()에서 기능을 제거하고 대신 now(재생 가능한) 인수 로 전달 하여 디자인을 향상시킬 수 있습니다 .
Toby Speight

114

24 시간 전에 일어난 사건은 하루 전일 것입니다

문제가 제대로 정의되지 않으면 테스트는 큰 도움이되지 않습니다. 달력 일을 시간 단위로 계산 한 날과 혼합 한 것 같습니다. 당신이 달력 일을 고수하면, 오전 1시에, 26 시간 전은 어제 가 아닙니다 . 그리고 시간을 고수하면 26 시간 전에 시간에 관계없이 하루 전으로 반올림합니다.


45
이것은 좋은 지적입니다. 요구 사항이 누락되었다고해서 반드시 구현 프로세스가 실패한 것은 아닙니다. 단지 요구 사항이 제대로 정의되지 않았 음을 의미합니다. (또는 때때로 인간의 실수를했을 수도 있습니다.)
Caleb

이것이 내가 만들고 싶은 대답입니다. 스펙을 "이 이벤트가이 달력 날짜 인 경우 델타를 현재 시간으로 표시합니다. 다른 날짜는 델타를 판별하기 위해서만 사용하십시오."
Baldrickk

1
나는이 대답이 진짜 문제를 지적하기 때문에 좋아합니다 : 시간과 날짜는 두 가지 다른 양입니다. 그것들은 관련되어 있지만 당신이 그것들을 비교하기 시작할 때, 상황은 실제로 빠르게 진행됩니다. 프로그래밍에서 날짜 및 시간 논리는 가장 어려운 것들 중 일부입니다. 나는 많은 날짜 구현이 기본적으로 날짜를 0:00 시점으로 저장하는 것을 좋아하지 않습니다. 많은 혼란을 초래합니다.
Pieter B

38

당신은 할 수 없습니다. TDD는 알고있는 가능한 문제로부터 사용자를 보호하는 데 유용합니다. 고려하지 않은 문제가 발생해도 도움이되지 않습니다. 가장 좋은 방법은 다른 사람이 시스템을 테스트하도록하는 것입니다.

관련 독서 : 대규모 소프트웨어의 경우 절대 제로 버그 상태에 도달 할 수 있습니까?


2
개발자가 아닌 다른 사람이 작성한 테스트는 항상 좋은 생각입니다. 즉, 버그가 프로덕션 환경에 들어가려면 두 당사자가 동일한 입력 조건을 간과해야합니다.
Michael Kay

35

내가 일반적으로 취하는 두 가지 방법이 있습니다.

먼저, 나는 에지 케이스를 찾습니다. 행동이 바뀌는 곳입니다. 귀하의 경우, 양의 정수 일 순서에 따라 여러 지점에서 동작이 변경됩니다. 엣지 케이스는 0, 1, 7 등입니다. 그런 다음 엣지 케이스와 그 주변에 테스트 케이스를 작성합니다. -1 일, 0 일, 1 시간, 23 시간, 24 시간, 25 시간, 6 일, 7 일, 8 일 등의 테스트 사례가 있습니다.

두 번째로 찾은 것은 행동 패턴입니다. 몇 주 동안의 논리에는 일주일 동안 특별한 처리가 있습니다. 표시되지 않은 다른 간격마다 비슷한 논리가있을 수 있습니다. 그러나이 논리는 며칠 동안 존재 하지 않습니다 . 나는 그 사건이 다른 이유를 입증 할 수 있거나 논리를 추가 할 때까지 의심으로 그것을 보았습니다.


9
이것은 종종 간과되는 TDD의 정말 중요한 부분이며 기사와 가이드에서 거의 언급하지 않았습니다. 버그의 90 %가 원인이라는 사실을 발견했을 때 엣지 케이스와 경계 조건을 테스트하는 것이 정말 중요합니다. -하나의 오류,
오버플로

2
@GoatInTheMachine-이 90 % 버그의 90 %는 일광 절약 시간제 전환에 관한 것입니다 ..... Hahaha
Caleb

1
먼저 등가 클래스 에서 가능한 입력을 나누고 클래스 경계에서 가장 중요한 경우를 결정할 수 있습니다. 우리의 노력 중 하나는 개발 노력보다 클 수 있습니다. 그 가치가 있는지 여부는 가능한 한 오류없이 소프트웨어를 제공하는 것이 얼마나 중요한지, 마감일이 얼마인지, 돈과 인내심이 얼마나 많은지에 달려 있습니다.
피터-모니카 복원 복원

2
이것이 정답입니다. 많은 비즈니스 규칙에 따라 다양한 값을 다른 방식으로 처리해야하는 간격으로 값 범위를 나누어야합니다.
abuzittin 길리 피르 카

14

당신은 할 수 TDD와 귀하의 요구 사항에 존재하는 논리적 오류를 잡을 수있어. 그러나 여전히 TDD가 도움이됩니다. 결국 오류를 발견하고 테스트 사례를 추가했습니다. 그러나 근본적으로, TDD는 단지 코드가 당신의 정신 모델을 준수 함을 보장합니다. 정신 모델에 결함이있는 경우 테스트 사례가이를 포착하지 못합니다.

그러나 버그를 수정하는 동안 이미 테스트 한 테스트 사례는 기존의 작동하는 동작이 손상되지 않았 음을 확인했습니다. 그것은 매우 중요합니다. 하나의 버그를 수정하는 것이 쉽지만 다른 버그를 소개합니다.

이러한 오류를 미리 찾으려면 일반적으로 동등성 클래스 기반 테스트 케이스를 사용하십시오. 이 원칙을 사용하면 모든 동등성 클래스에서 하나의 사례를 선택한 다음 모든 에지 사례를 선택합니다.

오늘, 어제, 며칠 전, 정확히 1 주일 전 및 몇 주 전에 날짜를 각 동등 클래스의 예로 선택합니다. 날짜를 테스트 할 때 테스트 에서 시스템 날짜를 사용 하지 않았지만 미리 결정된 날짜를 사용하여 비교했는지 확인하십시오. 이것은 또한 어떤 가장자리 케이스를 강조합니다 : 당신은 일의 어떤 임의의 시간에 테스트를 실행해야합니다 것입니다, 당신도 직접 직접 자정 전에, 자정 직후에 그것을 실행하고 것 자정. 이것은 각 테스트마다 4 번의 기본 테스트가 수행됨을 의미합니다.

그런 다음 시스템을 다른 모든 클래스에 체계적으로 추가합니다. 오늘 시험이 있습니다. 따라서 동작이 전환되기 직전과 직후에 시간을 추가하십시오. 어제도 마찬가지입니다. 일주일 전과 동일

모든 엣지 케이스를 체계적으로 열거하고 테스트 케이스를 작성함으로써 스펙에 세부 사항이 부족함을 발견하고 추가 할 수 있습니다. 날짜를 다루는 것은 사람들이 종종 잘못하는 것입니다. 사람들은 종종 다른 시간에 실행할 수 있도록 테스트 작성을 잊어 버립니다.

그러나 내가 작성한 대부분의 내용은 TDD와 거의 관련이 없습니다. 동등성 클래스를 작성하고 자신의 스펙이 충분히 상세하게 작성되는지에 관한 것입니다. 이것이 논리적 오류를 최소화하는 프로세스입니다. TDD는 귀하의 코드가 귀하의 정신 모델을 준수하는지 확인합니다.

테스트 사례를 생각해내는 것은 어렵다 . 동등성 기반 테스트는 그다지 끝나지 않으며 경우에 따라 테스트 케이스 수를 크게 늘릴 수 있습니다. 실제로는 이러한 테스트를 모두 추가 하는 것이 경제적으로 실행 가능하지 않은 경우가 많습니다 (이론 상으로는 수행해야 함).


12

내가 생각할 수있는 유일한 방법은 내가 결코 일어나지 않을 것이라고 생각하는 경우에 대해 많은 주장을 추가하고 (어제 전은 반드시 어제라고 생각한 것처럼) 지난 10 년 동안 매초마다 반복하여 확인하는 것입니다. 너무 복잡해 보이는 어설 션 위반

왜 안돼? 이것은 좋은 생각처럼 들립니다!

코드에 계약 (어설 션)을 추가하는 것은 정확성을 향상시키는 매우 확실한 방법입니다. 일반적으로 함수 입력에 대한 전제 조건 과 함수 반환에 대한 사후 조건 으로 추가합니다 . 예를 들어, 우리는 모든 반환 값은 사후 추가 할 수 있습니다 중 하나 "전 [단위]"형태 또는 "[수] [단위] 전 S"를. 잘 훈련 된 방식으로 수행되면 계약의한 설계로 이어지며 , 높은 보증 코드를 작성하는 가장 일반적인 방법 중 하나입니다.

비판적으로 계약은 테스트되지 않습니다. 그것들은 테스트와 마찬가지로 코드의 사양입니다. 그러나 계약을 통해 테스트 할 수 있습니다. 테스트 에서 코드를 호출하고 오류가 발생하지 않으면 테스트에 통과합니다. 지난 10 년의 1마다 반복되는 것은 약간입니다. 그러나 속성 기반 테스트 라는 다른 테스트 스타일을 활용할 수 있습니다 .

코드의 특정 출력을 테스트하는 대신 PBT에서 출력이 일부 속성을 준수하는지 테스트합니다. 예를 들면, 하나 개의 속성 reverse()기능은 목록이다 l, reverse(reverse(l)) = l. 이와 같은 테스트 작성의 단점은 PBT 엔진이 수백 개의 임의의 목록 (및 몇 가지 병리 적 목록)을 생성하고이 속성이 모두 있는지 확인할 수 있다는 것입니다. 그렇지 않은 경우 엔진은 실패 사례를 "축소하여"코드를 손상시키는 최소 목록을 찾습니다. 기본 PBT 프레임 워크로 가설 이있는 Python을 작성하는 것 같습니다 .

따라서 생각하기 어려운 까다로운 최첨단 사례를 찾는 좋은 방법을 원한다면 계약과 속성 기반 테스트를 함께 사용하면 많은 도움이됩니다. 이것은 물론 단위 테스트 작성을 대체하지는 않지만 증강시킵니다. 이는 엔지니어로서 할 수있는 최선의 방법입니다.


2
이것이 바로 이런 종류의 문제에 대한 올바른 해결책입니다. 유효한 출력 세트는 쉽게 정의 할 수 있으며 (정규 표현식을 매우 간단하게 /(today)|(yesterday)|([2-6] days ago)|...지정할 수 있음) 예상 출력 세트에없는 것을 찾을 때까지 임의로 선택된 입력으로 프로세스를 실행할 수 있습니다. 이 방법을 복용 것입니다 이 버그를 잡았으며, 하지 않을 버그가 사전에있을 수 있습니다 실현해야합니다.
Jules

@Jules 속성 확인 / 테스트 도 참조하십시오 . 나는 일반적으로 개발 과정에서 속성 테스트를 작성하여 예상치 못한 많은 사례를 다루고 일반적인 속성 / 불변량에 대해 생각하게합니다. 나는 회귀에 대한 일회성 테스트를 저장합니다 (저자의 이슈가 실례 인)
Warbo

1
테스트에서 많은 반복 작업을 수행하는 경우 시간이 오래 걸리면 단위 테스트의 주요 목표 중 하나를 상실합니다. 테스트를 빠르게 실행하십시오 !
CJ 데니스

5

이것은 약간의 모듈성을 추가하는 것이 유용한 예입니다. 오류가 발생하기 쉬운 코드 세그먼트를 여러 번 사용하는 경우 가능하면 함수로 묶는 것이 좋습니다.

def time_ago(delta, unit):
    delta_str = _number_to_text(delta) + " " + unit;
    if delta == 1:
        return delta_str + " ago"
    else:
        return delta_str = "s ago"

now = datetime.datetime.utcnow()
today = now.date()
if event_date.date() == today:
    return "Today"

yesterday = today - datetime.timedelta(1)
if event_date.date() == yesterday:
    return "Yesterday"

delta = (now - event_date).days

if delta < 7:
    return time_ago(delta, "day")

if delta < 30:
    weeks = math.floor(delta / 7)
    return time_ago(weeks, "week")

if delta < 365:
    months = math.floor(delta / 31)
    return time_ago(months, "month")

5

테스트 주도 개발은 도움이되지 못했습니다.

테스트를 작성하는 사람이 적대적이라면 TDD는 기술로 가장 효과적입니다. 페어 프로그래밍이 아닌 경우에는 어렵 기 때문에 이에 대해 생각하는 다른 방법은 다음과 같습니다.

  • 테스트중인 기능이 제대로 작동하는지 확인하기 위해 테스트를 작성하지 마십시오. 고의로 파괴하는 테스트를 작성하십시오.

이것은 TDD의 유무에 관계없이 올바른 코드를 작성하는 데 적용되는 실제 기술이며 실제 코드를 작성하는 것보다 복잡한 (아마도 그렇지 않은 경우) 것입니다. 연습해야 할 것, 간단하고 쉬운 단일 답변이 없습니다.

강력한 소프트웨어를 작성하는 핵심 기술은 효과적인 테스트 작성 방법을 이해하는 핵심 기술입니다.

함수의 전제 조건 이해-유효한 상태 (즉, 함수가 메소드 인 클래스의 상태에 대한 가정) 및 유효한 입력 매개 변수 범위-각 데이터 유형에는 가능한 값의 범위가 있습니다. 귀하의 기능에 의해 처리됩니다.

함수 입력에 대한 이러한 가정을 명시 적으로 테스트하고 더 이상 처리하지 않아도 위반이 기록되거나 발생하는지 및 / 또는 함수 오류가 발생하지 않도록하는 것만으로도 소프트웨어가 생산에 실패했는지 신속하게 알 수 있습니다. 오류에 견딜 수 있으며 적대적 시험 작문 기술을 개발하십시오.


NB. 사전 및 사후 조건, 변이체 등에 대한 전체 문헌과 속성을 사용하여 적용 할 수있는 라이브러리가 있습니다. 개인적으로 저는 그렇게 공식적으로가는 팬은 아니지만 그만한 가치가 있습니다.


1

이것은 소프트웨어 개발에있어 가장 중요한 사실 중 하나입니다. 버그가없는 코드를 작성하는 것은 완전히 불가능합니다.

TDD는 생각하지 않은 테스트 사례에 해당하는 버그를 도입하지 않아도됩니다. 또한 테스트를 실현하지 않고 잘못된 테스트를 작성한 다음 버기 테스트를 통과하는 잘못된 코드를 작성하지 않아도됩니다. 그리고 지금까지 만들어진 다른 모든 단일 소프트웨어 개발 기술에는 비슷한 구멍이 있습니다. 개발자로서 우리는 불완전한 인간입니다. 하루가 끝나면 100 % 버그가없는 코드를 작성할 수있는 방법이 없습니다. 그것은 결코 일어나지 않을 것입니다.

이것은 희망을 포기해야한다는 말이 아닙니다. 완벽하게 완벽한 코드를 작성하는 것은 불가능하지만 소프트웨어가 매우 실용적 일 수있는 아주 드문 경우에 나타나는 버그가 거의없는 코드를 작성할 수 있습니다. 실제로 버기 동작 나타내지 않는 소프트웨어 는 작성하는 것이 매우 가능합니다.

그러나이를 작성하려면 버그가있는 소프트웨어를 생산할 것이라는 사실을 받아 들여야합니다. 현대의 거의 모든 소프트웨어 개발 관행은 버그가 처음에 나타나는 것을 방지하거나 필연적으로 우리가 생산하는 버그의 결과로부터 스스로를 보호하는 데 중점을두고 있습니다.

  • 철저한 요구 사항을 수집하면 코드에서 잘못된 동작이 어떻게 보이는지 알 수 있습니다.
  • 깨끗하고 신중하게 설계된 코드를 작성하면 처음에 버그가 발생하는 것을 피하고 버그를 식별 할 때 쉽게 수정할 수 있습니다.
  • 작문 테스트를 통해 소프트웨어에서 발생할 수있는 최악의 많은 버그가 무엇인지 믿고 그 버그를 피할 수 있다는 것을 기록 할 수 있습니다. TDD는 코드보다 먼저 테스트를 생성하고, BDD는 요구 사항에서 테스트를 도출하며, 구식 단위 테스트는 코드를 작성한 후 테스트를 생성하지만 모두 최악의 회귀를 방지합니다.
  • 피어 리뷰는 코드가 변경 될 때마다 적어도 두 쌍의 눈이 코드를 보았으며 버그가 마스터에 얼마나 자주 들어가는 지 감소시킵니다.
  • 버그를 사용자 스토리로 취급하는 버그 추적기 또는 사용자 스토리 추적기를 사용한다는 것은 버그가 표시 될 때 버그를 추적하여 궁극적으로 사용자의 방식으로 일관된 방식으로 잊혀지지 않도록 처리한다는 것을 의미합니다.
  • 스테이징 서버를 사용한다는 것은 메이저 릴리스 이전에 모든 쇼 스토퍼 버그가 나타나고 처리 될 수 있음을 의미합니다.
  • 버전 관리를 사용하면 최악의 시나리오에서 주요 버그가있는 코드가 고객에게 제공되는 상황에서 긴급 롤백을 수행하고 정렬하는 동안 고객에게 안정적인 제품을 다시 제공 할 수 있습니다.

식별 한 문제에 대한 궁극적 인 해결책은 버그가없는 코드를 작성한다고 보장 할 수는 없으며,이를 수용하는 것입니다. 개발 프로세스의 모든 영역에서 업계 모범 사례를 채택하면 완벽하지는 않지만 작업에 필요한 수준 이상의 코드를 지속적으로 사용자에게 제공 할 수 있습니다.


1

당신은이 사건에 대해 이전에 생각하지 않았기 때문에 이에 대한 테스트 사례가 없었습니다.

이것은 항상 발생하며 정상입니다. 가능한 모든 테스트 사례를 만드는 데 많은 노력을 기울이는 것이 항상 상충 관계입니다. 모든 테스트 사례를 고려하기 위해 무한한 시간을 할애 할 수 있습니다.

항공기 자동 조종 장치의 경우 간단한 도구보다 훨씬 더 많은 시간을 소비합니다.

입력 변수의 유효 범위를 생각하고 이러한 경계를 테스트하는 데 도움이되는 경우가 종종 있습니다.

또한 테스터가 개발자와 다른 사람인 경우 종종 더 중요한 사례가 발견됩니다.


1

(그리고 코드에서 UTC를 균일하게 사용하더라도 시간대와 관련이 있다고 생각합니다)

그것은 아직 단위 테스트가없는 코드의 또 다른 논리적 실수입니다 :)-메소드는 비 UTC 시간대의 사용자에게 잘못된 결과를 반환합니다. 계산하기 전에 "현재"날짜와 이벤트 날짜를 모두 사용자의 현지 시간대로 변환해야합니다.

예 : 호주에서는 현지 시간으로 오전 9시에 이벤트가 발생합니다. 오전 11시에 UTC 날짜가 변경되었으므로 "어제"로 표시됩니다.


0
  • 다른 사람이 테스트를 작성하도록하십시오. 이렇게하면 구현에 익숙하지 않은 누군가가 생각하지 않은 드문 상황을 확인할 수 있습니다.

  • 가능하면 테스트 사례를 컬렉션으로 주입하십시오. 이 같은 다른 행을 추가로 쉽게와 같은 다른 검사를 추가 할 수 있습니다 yield return new TestCase(...). 이는 탐색 적 테스트 방향으로 진행되어 테스트 사례 작성을 자동화 할 수 있습니다 . "1 주일 전에 코드가 무엇을 리턴하는지 봅시다."


0

모든 테스트가 통과되면 버그가 없다고 오해하는 것 같습니다. 실제로 모든 테스트가 통과되면 알려진 모든 동작이 올바른 것입니다. 알 수없는 동작이 올바른지 여부는 여전히 알 수 없습니다.

TDD에 코드 적용 범위를 사용하고 있기를 바랍니다. 예기치 않은 동작에 대한 새로운 테스트를 추가하십시오. 그런 다음 예기치 않은 동작에 대한 테스트 만 실행하여 실제로 코드를 통과하는 경로를 확인할 수 있습니다. 현재 동작을 알고 나면이를 수정하여 변경할 수 있으며 모든 테스트가 다시 통과하면 올바르게 수행 한 것입니다.

이것은 여전히 ​​코드에 버그가 없음을 의미하는 것이 아니며 이전보다 더 우수하다는 것을 의미하며 알려진 모든 동작이 다시 한번 정확합니다!

TDD를 올바르게 사용한다고해서 버그가없는 코드를 작성할 수 있다는 의미는 아닙니다. 버그를 적게 씁니다. 당신은 말한다 :

요구 사항은 비교적 명확했습니다

이는 요일이 아닌 어제 행동이 요구 사항에 지정되었음을 의미합니까? 서면 요구 사항을 놓쳤다면 그것은 당신의 잘못입니다. 코딩 할 때 요구 사항이 불완전하다는 것을 깨달았다면 좋습니다. 요구 사항을 해결 한 모든 사람이이 사례를 놓쳤다면 다른 사람보다 나쁘지 않습니다. 누구나 실수를 저지르고 미묘할수록 놓치기 쉽습니다. 여기서 가장 중요한 것은 TDD 모든 오류를 방지 하지는 않는다는 것입니다 !


0

간단한 소스 코드에서도 논리적 실수를 저지르는 것은 매우 쉽습니다.

예. 테스트 주도 개발은이를 변경하지 않습니다. 실제 코드와 테스트 코드에서도 버그를 생성 할 수 있습니다.

테스트 주도 개발은 도움이되지 못했습니다.

아,하지만 했어요! 우선, 버그를 발견했을 때 이미 완전한 테스트 프레임 워크가 있으며 테스트에서 버그 (및 실제 코드)를 수정해야했습니다. 둘째, 처음에 TDD를 수행하지 않은 경우 얼마나 많은 버그가 있었는지 알 수 없습니다.

또한 그러한 버그를 피할 수있는 방법을 알 수 없다는 것이 걱정입니다.

당신은 할 수 없습니다. NASA조차도 버그를 피할 수있는 방법을 찾지 못했습니다. 우리는 덜 인간도 마찬가지입니다.

코드를 작성하기 전에 더 생각하고

그것은 잘못된 것입니다. TDD의 가장 큰 장점 중 하나는 생각 이 적어 코딩이 가능하다는 것입니다. 모든 테스트는 최소한 회귀를 잘 잡아 내기 때문입니다. 또한, 특히 TDD를 사용하더라도 버그가없는 코드를 처음에는 제공 하지 않을 것입니다 (또는 개발 속도가 중단 될 수 있습니다).

내가 생각할 수있는 유일한 방법은 내가 결코 일어나지 않을 것이라고 생각하는 경우에 대해 많은 주장을 추가하고 (어제 전은 반드시 어제라고 생각한 것처럼) 지난 10 년 동안 매초마다 반복하여 확인하는 것입니다. 너무 복잡해 보이는 어설 션 위반

이것은 현재 실제로 필요한 것만 코딩한다는 교리와 분명히 충돌합니다. 그런 경우가 필요하다고 생각했기 때문입니다. 중요하지 않은 코드였습니다. 30 분 동안 궁금해하는 것 외에는 아무런 손상이 없다고했습니다.

미션 크리티컬 코드의 경우 실제로 말한 것을 수행 할 수 있지만 일상적인 표준 코드에는 적합하지 않습니다.

처음에이 버그를 만들지 않으려면 어떻게해야합니까?

당신은하지 않습니다. 대부분의 회귀를 찾기 위해 테스트를 신뢰합니다. 당신은 실제 코딩 전 / 중에 테스트를 작성하고, (녹색) 리 팩터 사이클을 유지하고, (녹색) 스위치를 만들기 위해 필요한 최소한의 양을 구현합니다. 이것은 적어도 긍정적 인 테스트 커버리지로 끝날 것입니다.

버그가 발견되지 않으면 해당 버그를 재현하는 테스트를 작성하고 최소한의 작업으로 버그를 수정하여 해당 테스트를 빨간색에서 녹색으로 바꿉니다.


-2

아무리 노력해도 코드에서 가능한 모든 버그를 잡을 수는 없다는 것을 방금 알게되었습니다.

따라서 이것이 의미하는 것은 모든 버그를 잡으려고 시도하는 것이 무의미한 연습이므로, 더 나은 코드를 작성하는 방법으로 TDD와 같은 기술, 버그가 적은 코드, 버그가 0이 아닌 코드 만 사용해야합니다.

다시 말해, 이러한 기술을 사용하는 데 시간을 덜 소비하고 개발 시간을 단축시키는 버그를 찾기 위해 다른 방법으로 시간을 절약 할 수 있습니다.

통합 테스트 또는 테스트 팀, 시스템 테스트, 로그 기록 및 분석과 같은 대안.

모든 버그를 잡을 수 없다면, 당신을 지나치는 버그의 영향을 완화시키기위한 전략을 세워야합니다. 어쨌든이 작업을 수행 해야하는 경우 더 많은 노력을 기울이면 처음부터 중지하려고 시도하는 것보다 헛된 것입니다.

결국, 테스트를 작성하는 데 시간이 많이 걸리고, 고객에게 제품을 제공 한 첫날에는 특히 버그를 찾고 해결하는 방법에 대한 단서가없는 경우 무의미합니다. 사후 및 배달 후 버그 해결은 매우 중요하며 대부분의 사람들이 단위 테스트 작성에 쓰는 것보다 더 많은주의를 기울여야합니다. 복잡한 비트에 대한 단위 테스트를 저장하고 완벽하게 시도하지 마십시오.


이것은 매우 패배합니다. That in turn means you should spend less time using these techniques하지만 방금 버그를 줄이는 데 도움이된다고 했어요?!
JᴀʏMᴇᴇ

@ JᴀʏMᴇᴇ 더 실용적으로 어떤 기술을 사용 하는가에 대한 실용 주의적 태도. 코드에서보다 테스트를 작성하는 것보다 10 배나 시간을 소비 하고 여전히 버그 가 있음을 자랑스럽게 생각하는 사람들을 알고 있습니다 . 테스팅 기술에 대한 정보는 필수적입니다. 그리고 통합 테스트는 어쨌든 사용해야하므로 단위 테스트보다 더 많은 노력을 기울여야합니다.
gbjbaanb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.