알고리즘 문제에 대한 접근 방식과 같은 TDD


10

더 나은 솔루션을 찾으려고했기 때문에 Codility로 알고리즘 테스트에 실패했으며 결국 아무것도 없었습니다.

그래서 TDD와 비슷한 접근법을 사용할 수 있다고 생각하게 했습니까? 즉, 비슷한 방식으로 점진적으로 솔루션을 개발할 수 있다면?

정렬 알고리즘을 작성하는 경우 표준 Bubblesort에서 2-way bubblesort로 이동할 수 있지만 Quicksort와 같은 고급 기능은 "quantum leap"이지만 최소한 테스트 데이터가 있으면 쉽게 확인할 수 있습니다.

그러한 테스트에 대한 다른 팁? 다음에 내가 할 한 가지는 내부 루프보다 더 많은 메소드 / 함수를 사용하는 것입니다. 예를 들어 정렬시 종종 스왑이 필요합니다. 그것이 메소드라면 호출 코드를 수정하면됩니다. 파생 클래스로 더 고급 솔루션을 가질 수도 있습니다.

"알고리즘"대 "정상"문제는 시간 복잡성이 중요한 문제를 의미합니다. 따라서 TDD에서와 같이 더 많은 테스트를 통과하는 대신 "더 나은 동작"을 수행하게됩니다.

"TDD와 유사"이란 의미는 다음과 같습니다.

  1. 수동 테스트에서 증분 시간을 절약하기 위해 비교적 자동 테스트를 작성하십시오.
  2. 증분 개발.
  3. 회귀 테스트, 코드가 깨 졌는지 또는 최소한 기능이 증분간에 변경되는지 감지하는 기능.

나는 당신이 비교하면 이해하기 쉬워야한다고 생각합니다.

  1. 쉘 정렬을 직접 작성
  2. bubblesort에서 quicksort로 점프 (전체 다시 쓰기)
  3. 단방향 버블 정렬에서 쉘 정렬로 증분 이동 (가능한 경우).

"TDD와 유사하다"는 무슨 뜻입니까? 정렬 기능을 개발하기 위해 TDD를 사용하려고 시도한 다음 정렬 알고리즘을보다 효율적인 알고리즘으로 대체 할 때 단위 테스트를 사용하여 기능이 여전히 유효한지 검증 할 수는 있지만 다른 질문이있는 것 같습니까?
Doc Brown

"점진적으로":-)-마지막 문장이 "그래서 대신에 ..."추가됨
Olav

2
물론 작동하는 (아주 효율적이지 않은) 솔루션으로 많은 문제를 해결 한 다음 개선 할 수 있습니다. 이것은 알고리즘이나 프로그래밍 문제로 제한되지 않으며 TDD와 공통점이 아닙니다. 이것이 귀하의 질문에 대답합니까?
Doc Brown

@DocBrown 아니오-Bubblesort / Quicksort 예제를 참조하십시오. 증분 방식은 여러 유형의 문제에 효과적이므로 TDD는 "작동"합니다. 알고리즘 문제는 다를 수 있습니다.
Olav

"TDD에 의한 것이 아니라"TDD가 점진적인 접근 방식 인 것처럼 "증분 방식으로 알고리즘 설계 문제를 해결할 수 있는가"를 의미 했습니까? 명확히하십시오.
Doc Brown

답변:


9

불행히도 작동하지 않은 TDD로 Ron Jeffries의 스도쿠 솔버를 만들려는 시도를 참조하십시오 .

알고리즘은 알고리즘 설계 원칙에 대한 상당한 이해가 필요합니다. 이러한 원칙을 통해 Peter Norvig와 같은 계획을 통해 점진적으로 진행할 수 있습니다 .

사실상 사소한 설계 노력이 필요한 알고리즘의 경우 거의 항상 노력이 점진적으로 증가합니다. 그러나 알고리즘 디자이너의 눈에는 아주 작은 각 "증분" 은이 특정 알고리즘 제품군에 대해 동일한 전문 지식이나 지식을 가지고 있지 않은 사람에게 양자 도약처럼 보입니다 (구문을 빌리기 위해).

이것이 CS 알고리즘의 기본 교육과 많은 알고리즘 프로그래밍 실습이 똑같이 중요한 이유입니다. 특정 "기술"(작은 알고리즘의 빌딩 블록)이 존재한다는 것을 아는 것은 이러한 점진적인 양자 도약을 향한 먼 길입니다.


그러나 알고리즘의 점진적 진행과 TDD 사이에는 중요한 차이점이 있습니다.

차이점은 JeffO 가 언급 한 입니다. 출력 데이터 의 정확성을 검증 하는 테스트 는 동일한 알고리즘의 다른 구현 (또는 동일한 솔루션을 제공하기 위해 경쟁하는 다른 알고리즘)간에 성능 을 주장하는 테스트와는 별개입니다 .

TDD에서는 테스트 형식으로 새로운 요구 사항을 추가하며이 테스트는 처음에는 통과하지 않습니다 (빨간색). 그런 다음 요구 사항이 충족됩니다 (녹색). 마지막으로 코드가 리팩터링됩니다.

알고리즘 개발에서 요구 사항은 일반적으로 변경되지 않습니다. 결과 정확성 검증 테스트는 먼저 작성되거나 알고리즘의 초안 (고신뢰하지만 느리게) 구현이 완료된 직후에 작성됩니다. 이 데이터 정확성 테스트는 거의 변경되지 않습니다. TDD 의식의 일부로 실패 (빨간색)로 변경되지 않습니다.

그러나이 측면에서 데이터 분석 요구 사항 (입력 세트 및 예상 결과 모두)은 사람이 이해하기에 느슨하게 정의되기 때문에 데이터 분석은 알고리즘 개발과 분명히 다릅니다. 따라서 요구 사항은 기술 수준에서 자주 변경됩니다. 이러한 빠른 변화는 알고리즘 개발과 일반적인 소프트웨어 응용 프로그램 개발 사이의 데이터 분석을 가능하게합니다. 여전히 알고리즘이 무겁지만 요구 사항도 프로그래머의 취향에 따라 너무 빠릅니다.

요구 사항이 변경되면 일반적으로 다른 알고리즘이 필요합니다.

알고리즘 개발에서 성능 비교 테스트를 실패 (빨간색)로 변경 (조임)하는 것은 어리석은 일입니다. 성능을 향상시키는 알고리즘의 잠재적 변경에 대한 통찰력을 제공하지는 않습니다.

따라서 알고리즘 개발에서 정확성 테스트와 성능 테스트는 모두 TDD 테스트가 아닙니다. 대신 둘 다 회귀 테스트 입니다. 특히 정확성 회귀 테스트는 정확성을 잃을 알고리즘을 변경하지 못하게합니다. 성능 테스트를 통해 알고리즘이 느리게 실행되도록 알고리즘을 변경할 수 없습니다.

"적색-녹색-리 팩터"의식이 알고리즘 개발 의 사고 과정에 특별히 필요 하지 않거나 특히 유익 하지 않다는 점을 제외하고는 여전히 TDD를 개인 작업 스타일로 통합 할 수 있습니다 .

알고리즘 개선은 실제로 현재 알고리즘의 데이터 흐름도에 임의의 (정확하지는 않지만) 순열을 만들거나 이전에 알려진 구현 사이에서 그것들을 혼합하고 일치시킴으로써 발생한다고 주장합니다.


테스트 세트에 점진적으로 추가 할 수있는 여러 요구 사항이있는 경우 TDD가 사용됩니다 .

또는 알고리즘이 데이터 중심 인 경우 각 테스트 데이터 / 테스트 사례를 증 분식으로 추가 할 수 있습니다. TDD도 유용 할 것입니다. 이러한 이유로 "새로운 테스트 데이터 추가-이 데이터를 올바르게 처리 할 수 ​​있도록 코드 개선-리팩터링"의 "TDD- 유사"접근 방식은 개방형 데이터 분석 작업에도 적용되며 알고리즘의 목표는 사람에게 설명됩니다. 중심 단어와 그것의 성공 측정도 인간이 정의한 용어로 판단됩니다.

한 번의 시도로 수십 또는 수백 가지의 모든 요구 사항을 충족시키는 것 보다 압도적 인 방법을 가르쳐야합니다 . 다시 말해, 솔루션의 초기 초안을 구현하는 동안 특정 요구 사항 또는 스트레치 목표를 일시적으로 무시할 수 있음을 지시 할 때 TDD가 활성화됩니다 .

TDD는 컴퓨터 과학을 대체하지 않습니다. 그것은이다 심리적 목발 프로그래머는 한 번에 여러 요구 사항을 충족해야하는 충격을 극복하는 데 도움이됩니다.

그러나 올바른 결과를 제공하는 구현이 이미있는 경우 TDD는 목표를 달성했으며 코드를 리팩토링하거나 다른 프로그래머 사용자에게 전달할 준비가 된 것으로 간주합니다. 어떤 의미에서, 코드가 "충분히 좋다"는 신호를 객관적으로 제공함으로써 (모든 정확성 테스트를 통과하기 위해) 코드를 조기에 최적화하지 않는 것이 좋습니다.


TDD에서는 "미세 요구 사항"(또는 숨겨진 품질)에 중점을 둡니다. 예를 들어 매개 변수 유효성 검사, 어설 션, 예외 발생 및 처리 등 TDD는 일반적인 소프트웨어 실행 과정에서 자주 실행되지 않는 실행 경로의 정확성을 보장합니다.

특정 유형의 알고리즘 코드에도 이러한 것들이 포함되어 있습니다. 이들은 TDD에 적합합니다. 그러나 알고리즘의 일반적인 워크 플로는 TDD가 아니기 때문에 구현 코드가 이미 (적어도 부분적으로) 작성된 후에 이러한 테스트 (매개 변수 유효성 검사, 어설 션 및 예외 발생 및 처리)가 작성되는 경향이 있습니다.


게시물에서 처음 인용 된 두 단어 ( "Uncle Bob")는 무엇을 의미합니까?
Robert Harvey

@RobertHarvey Bob 아저씨에 따르면 TDD는 알고리즘 발견에 사용될 수 있습니다. 다른 광도에 따르면 작동하지 않습니다. 나는 사람들이 긍정적이고 부정적인 예에 ​​대한 균형 잡힌 정보를 얻도록 두 가지 모두 언급해야한다고 생각했다.
rwong

확인. 그러나 당신은 나의 혼란을 이해합니까? 첫 번째 단락은 "Uncle Bob"이라는 단어를 말하는 사람을 인용하는 것으로 보입니다. 누가 말하는거야?
Robert Harvey

@RobertHarvey 주문이 준수되었습니다.
rwong

2

문제의 경우 두 가지 테스트가 있습니다.

  1. 알고리즘이 여전히 정확한지 테스트합니다. 예를 들어 올바르게 정렬되어 있습니까?
  2. 성능 비교 테스트-성능이 향상되었습니다. 이것은 까다로울 수 있으므로 동일한 컴퓨터, 동일한 데이터에서 테스트를 실행하고 다른 리소스의 사용을 제한하는 데 도움이됩니다. 전용 기계가 도움이됩니다.

테스트 대상 또는 전체 테스트 범위는 논란의 여지가 있지만, 세부 조정 (많은 변경)이 필요한 애플리케이션의 복잡한 부분은 자동화 된 테스트의 완벽한 후보라고 생각합니다. 응용 프로그램의 이러한 부분은 일반적으로 매우 일찍 식별됩니다. 이 부분에 TDD 방식을 사용하는 것이 좋습니다.

복잡한 문제를 해결할 수 있다고해서 다양한 접근법을 시도하는 것을 꺼려해서는 안됩니다. 이 영역에서 자동 테스트를 수행하면 도움이됩니다. 적어도 당신은 당신이 그것을 악화시키지 않는 것을 알게 될 것입니다.


1

따라서 TDD에서와 같이 더 많은 테스트를 통과하는 대신 "더 나은 동작"을 수행하게됩니다.

일종의.

런타임 및 복잡성을 테스트 할 수 있습니다. 런타임 테스트는 시스템 리소스에 대한 경합을 허용하기 위해 약간의 관용이 필요합니다. 그러나 많은 언어에서 메소드를 대체하거나 삽입하고 실제 함수 호출을 계산할 수도 있습니다. 당신이 확신한다면, 현재의 알고리즘이 최적이며, 당신은 단순히이 요구하는 시험을 도입 할 수 sort()호출 compare()순진한 구현보다 적은 시간.

또는 sort()두 세트를 비교 compare()하여 대상 복잡성 (일부 불일치가 예상되는 경우)에 따라 통화 규모를 확장 할 수 있습니다.

그리고 이론적 으로 일련의 크기 NN*log(N)비교 이상을 요구하지 않는다는 것을 입증 할 수 있다면 이미 작동 하는 호출 로 제한하는 것이 합리적 일 있습니다 ...sort()N*log(N)compare()

그러나 ...

성능 또는 복잡성 요구 사항을 충족한다고해서 기본 구현이 {AlgorithmX} 인 것은 아닙니다 . 그리고 나는 이것이 일반적으로 괜찮다고 주장합니다. 구현이 중요한 복잡성, 성능 또는 리소스 요구 사항을 포함하여 요구 사항을 충족시키는 경우 어떤 알고리즘을 사용하든 상관 없습니다.

그러나 특정 알고리즘을 사용하려면 더 지루하고 깊이를 더해야합니다. 같은 것들..

  • 및 (또는 무엇이든) 예상 되는 정확한 수의 전화 가 이루어 지도록 보장compare()swap()
  • 모든 주요 기능 / 방법을 래핑하고 예측 가능한 데이터 세트로 호출이 정확히 예상되는 순서로 발생하도록 보장
  • N 단계마다 작업 상태를 검사하여 예상대로 정확하게 변경되었는지 확인

그러나 {AlgorithmX} 가 특히 사용 되도록하려는 경우 {AlgorithmX}의 실제 사용 여부보다 테스트하는 것이 더 중요한 {AlgorithmX}의 기능이있을 것입니다 ...


또한 TDD는 소프트웨어 개발 에 대한 연구, 사고 또는 계획 의 필요성을 부정하지 않습니다 . 또한 자동화 된 테스트 제품군 에서 인터넷 검색 및 화이트 보드를 쉽게 주장 할 수없는 경우에도 브레인 스토밍 및 실험의 필요성을 부정하지 않습니다 .


작업 수에 대한 한계를 주장 할 수있는 가능성에 관한 탁월한 지적. 나는 그것이 TDD에서 사용될 수있는 것 (모의, 스터브 및 스파이)의 힘이라고 주장 할 것이다. 이것은 다른 종류의 테스트에서도 사용될 수있다.
rwong

테스트 시나리오에서 코드를 작성하기 전에 테스트를 작성하는 데 큰 의미가 없습니다. 기능적 기준이 충족 된 후 일반적으로 마지막 기준입니다. 때로는 임의의 숫자를 처음부터 최악의 경우로 수행 할 수 있지만 영리한 인쇄물에 비해 테스트 작성에 오랜 시간이 걸립니다. (일부 통계를 사용하면 테스트 중에는 일반 코드를 작성할 수 있지만 실제로는 특정 경우에 성능이 갑자기 저하되는지 알고 싶을 것입니다.
Olav

codility.com/programmers/task/stone_wall 을 보면 예를 들어 매우 긴 기간 동안 작업해야하는 특수한 경우를 제외하고 N 개 이상의 복잡성이 있는지 알 수 있습니다.
Olav

@Olav 할 ... "쓰기 시험은 일부 영리한 출력물에 비해 시간이 오래 걸릴 것" 한번 .. 으음 ... 아마 뿐만 아니라 매우 논쟁의 여지가. 모든 빌드에서 반복적으로 수행하려면? ... 기필코 아니다.
svidgen

@Olav "실제로 어떤 경우에는 성능이 갑자기 저하되는지 알고 싶습니다." 라이브 서비스에서는 New Relic과 같은 것을 사용 하여 특정 방법뿐만 아니라 전반적인 성능 을 모니터링 합니다. 이상적으로는 테스트 전에 성능 결정적인 모듈 및 방법 이 배포 전에 기대치를 충족하지 못하는 경우를 알려줍니다 .
svidgen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.