2009-05-19 6 views
6

static/strong-typed 프로그래밍 언어에 대한 가장 중요한 것은 리팩토링에 도움이된다는 것입니다. API를 변경하면 컴파일러에서 변경 내용을 알려줍니다. 부서졌다.정적/강력한 타이핑 및 리팩터링

런타임/약형 언어에서 코드를 작성한다고 상상할 수 있지만 컴파일러의 도움 없이는 리팩토링을 상상할 수 없으며 리팩토링하지 않고 수만 줄의 코드를 작성한다고 상상할 수 없습니다.

사실인가요?

+0

당신은 여전히 ​​리팩터링을 할 것입니다. IDE/컴파일러 대신에 단위 테스트를 사용하기 만하면됩니다. 일단 익숙해지면 실제로 그렇게 나쁜 것이 아닙니다. –

답변

13

유형 검사시 검사 방법이 서로 다를 수 있습니다. 런타임 타이핑이 반드시 약한 것은 아닙니다.

정적 유형의 주요 이점은 정확히 말하면 철저합니다. 모든 호출 사이트가 컴파일러에 맡기는 것으로 형식에 맞다고 확신 할 수 있습니다.

정적 유형의 주요 제한 사항은 표현할 수있는 제약 사항이 제한된다는 것입니다. 이것은 언어에 따라 다르며, 대부분의 언어는 상대적으로 간단한 유형 시스템 (c, java)과 매우 강력한 유형 시스템 (haskell, cayenne)을 사용합니다.

이 제한으로 인해 유형 자체로 충분하지 않습니다. 예를 들어, Java 형에서는, 형태의 이름의 검사에 다소 제한이 있습니다. 즉, 확인하려는 제약 조건의 의미는 일종의 명명 스키마로 인코딩되어야하므로 자바 코드에 공통적 인 보간과 보일 플레이트가 많이 있습니다. C++은 템플릿이 좀 더 표현력을 허용하지만 종속 유형으로 할 수있는 일에 거의 가깝지는 않는다는 점에서 조금 나아졌습니다. 좀 더 강력한 유형의 시스템에 대한 단점이 무엇인지 확실하지 않지만, 분명히 사람들이 업계에서 이들을 사용하고 있어야합니다.

정적 유형 지정을 사용하는 경우에도 관심있는 모든 항목을 검사 할만큼 충분히 표현할 수는 없으므로 테스트를 작성해야합니다.정적 타이핑이 보일러 플레이트에서 요구하는 것보다 많은 노력을 절약 할 수 있는지 여부는 연령대에 따라 격렬한 논쟁이되며 모든 상황에 대한 간단한 대답은 없다고 생각합니다. 두 번째 질문에 관해서는

:

우리는 어떻게 다시 요인을 할 수 안전하게 런타임 타입 언어에?

답변은 테스트입니다. 테스트는 중요한 모든 사례를 다루어야합니다. 도구는 테스트가 얼마나 철저한지를 측정하는 데 도움을 줄 수 있습니다. 보험 보상 검사 도구를 사용하면 코드가 더 엄격하게 테스트에 포함되는지 여부를 알 수 있습니다. 테스트 변이 도구 (jester, heckle)는 테스트가 논리적으로 불완전한지를 알려줍니다. 수락 테스트를 통해 작성한 내용이 요구 사항과 일치하는지 확인하고 마지막 회귀 및 성능 테스트를 통해 각 새 버전의 제품이 마지막 품질을 유지하는지 확인합니다.

적절한 테스트를 수행하는 것과 정교한 유형의 회귀 분석에 의존하는 것에 대한 훌륭한 점 중 하나는 디버깅이 훨씬 간단해진다는 것입니다. 테스트를 수행 할 때 테스트에서 특정 컴파일러 오류 문 (C++ 템플리트 오류라고 생각하는 것)이 아닌 자신이 수행중인 작업을 명확하게 표현하는 특정 실패한 어설 션을 얻습니다.

당신이 사용하는 도구가 무엇이든간에 : 자신감이있는 코드를 작성하려면 노력이 필요합니다. 대부분의 테스트를 작성해야 할 가능성이 큽니다. 항공 우주 또는 의료 제어 소프트웨어와 같이 버그에 대한 벌금이 매우 높거나 인 경우 공식적인 수학적 방법을 사용하여 소프트웨어의 동작을 증명해야하므로 개발 비용이 많이 듭니다.

+0

실제로 원하는 정적 유형 시스템에서 누락 된 사항을 자세히 설명해 주시겠습니까? 제가 말할 수있는 한, 타입 시스템에 속할 수있는 어떤 부족함도 느끼지 못하고 있습니다. 나는 뭔가를 놓치고 그것을 알아 차리지 못할 수도 있습니다. 그런 경우에 당신이 나에게 그것을 지적하는 것이 매우 가치있을 것입니다. –

+0

@ 존 : 궁극의 람다에있는 누군가가 당신에게 더 잘 대답 할 수는 있지만 제한된 이해로 인해 C++ 입력의 큰 약점은 집계에 대한 제약입니다. Alexandrescue를 해킹하는 C++ 템플릿은 꽤 멀리까지 갈 수 있지만, 런타임 검사에 의존하는 컨테이너/배열 관련 코드가 여전히 상당히 많이 있다고 생각합니다. 예를 들어, 벡터의 모양을 제약하고 싶다면 어떻게해야할까요? 또는 문자열의 길이를 범위로 제한 하시겠습니까? 종속 유형은 이런 종류의 것을 표현할 수 있습니다. –

+0

'종속 형'으로 언어를 사용하지 않았습니다 ... '런타임 형 입력'에 대한 제 생각은 JavaScript와 같습니다! – ChrisW

1

나는 리팩토링이 컴파일러가 검사 할 수있는 것 이상으로 정적으로 타입이 지정된 언어에서도 가능하다고 말합니다. 리팩토링은 외부 동작에 영향을주지 않고 프로그램의 내부 구조를 변경하는 것입니다. 동적 인 언어에서도, 당신이 기대하고 기대할 수있는 것들이 있습니다. 컴파일러의 지원을 조금 잃어 버릴 수 있습니다.

5

나는 당신의 정서에 완전히 동의합니다. 동적으로 유형을 지정하는 언어가 잘하는 유연성은 실제로 코드를 유지하기가 어렵게 만드는 것입니다. 실제로, 코드를 실제로 변경하지 않고 데이터 유형이 변경되지 않으면 계속 작동하는 프로그램 같은 것이 있습니까?

한편, 전달되는 변수의 유형을 확인할 수 있으며 예상되는 유형이 아닌 경우 실패 할 수 있습니다. 이런 경우를 근본적으로 해결하기 위해 코드를 실행해야하지만, 적어도 뭔가 알려줄 것입니다.

Google의 내부 도구가 실제로 컴파일을 수행하고 아마도 자바에 유형을 확인한다고 생각합니다. 나는 그 도구들을 가지고 있었으면 좋겠다.

+1

기본적으로 Google Web Toolkit (http://code.google.com/webtoolkit/)에 대해 이야기하지 않습니까? –

+0

"실제로 코드를 변경하지 않고 데이터 유형이 사소한 방법으로 변경되면 계속 작동하는 프로그램 같은 것이 있습니까?" 예, 구조적 타이핑 (일명 오리 유형 지정)을 지원하는 모든 언어에서이를 자주 볼 수 있습니다. 반드시 정적이거나 동적 인 것은 아닙니다. 예를 들어, C++ 제네릭 함수는 사용하는 형식의 특정 측면 만 신경하므로 함수를 변경하지 않아도되는 많은 인수 형식 변경이 가능합니다. –

1

var을 C# 3.0에서 사용하면 얻을 수있는 이점 중 하나는 은 코드를 변경하지 않고도 형식을 자주 변경한다는 것입니다. 유형은 여전히 ​​동일하게 보일 필요가 있습니다. 동일한 이름을 가진 특성이 존재해야하며, 동일하거나 유사한 특성을 가진 메소드가 여전히 존재해야합니다. 그러나 ReSharper와 같은 것을 사용하지 않아도 완전히 다른 유형으로 변경할 수 있습니다.

2

필자는 원시 Perl 프로그래머이므로 정적 유형의 그물을 사용하여 프로그래밍 한 적이 한 번도 없습니다. OTOH 나는 그 (것)들에 결코 프로그램하지 않았다 그래서 나는 그들의 이득에 말할 수 없다. 내가 말할 수있는 것은 리팩터링과 같은 것입니다.

정적 유형이 부족하여 리팩토링에 문제가 있다는 것을 발견하지 못했습니다. 내가 발견 한 문제는 리팩터링이 없다는 것이다. 브라우저. 동적 언어는 실제로 코드를 실행하기 전에 코드가 실제로 무엇을 할 것인지를 모르는 문제가 있습니다. 펄은 이것보다 더 많은 것을 가지고 있습니다. Perl은 매우 복잡하고 거의 해석 할 수없는 문법을 가지고 있다는 추가적인 문제가있다. 결과 : 리팩토링 도구가 없습니다 (비록 they're working very rapidly on that). 최종 결과는 손으로 리팩토링해야합니다. 이것이 바로 버그를 소개합니다.

나는 그 (것)들을 붙잡는 시험이 ... 보통있다. 나는 그것을 테스트하기 위해 코드를 리팩터링해야한다는 닭고기/달걀 문제와 함께 테스트되지 않은 많은 테스트 할 수없는 코드의 찌그러진 더미 앞에서 자주 발견하지만 리펙토링하기 위해 테스트해야합니다. Ick. 이 시점에서 필자는 무언가를 깨뜨리지 않았 음을 확인하기 위해 "프로그램 출력이 이전과 똑같은 결과를 나타 냅니까"라는 매우 벙어리 인 상위 레벨을 작성해야합니다.

Java 또는 C++ 또는 C#에서 구상 된 정적 유형은 실제로 프로그래밍 문제의 작은 클래스 만 해결합니다. 인터페이스가 올바른 레이블을 사용하여 데이터 비트를 전달하도록 보장합니다. 하지만 콜렉션을 얻은 것이 콜렉션에 있다고 생각하는 데이터가 있다는 것을 의미하지는 않습니다. 정수를 얻은다고해서 올바른 정수가 있다는 것을 의미하지는 않습니다. 메소드는 User 객체를 사용하지만 로그인 한 사용자입니까?

예 : public static double sqrt(double a)signature for the Java square root function입니다. 음수에는 제곱근이 적용되지 않습니다. 서명에서 그것을 어디에서 말하는가? 그렇지 않습니다. 심지어 더 나쁜 것은, 그 기능이하는 일이 무엇이라고 말하는가? 서명은 어떤 유형을 취하고 무엇을 반환하는지 만 알려줍니다. 그 사이에 일어나는 일에 대해서는 아무 것도 말하지 않고 흥미있는 코드가 살아있는 곳입니다.어떤 사람들은 design by contract을 사용하여 전체 API를 캡처하려고 시도했으며, 이는 함수의 입력, 출력 및 부작용 (또는 그 부족)에 대한 런타임 테스트 포함으로 광범위하게 설명 될 수 있습니다 ... 그러나 그것은 또 다른 쇼입니다.

API는 기능 서명 (기능이없는 경우 Javadocs에서 설명이 포함 된 산물을 모두 필요로하지 않음) 이상이며 API를 변경하는 것보다 훨씬 더 리팩토링입니다.

정적으로 형식화되고 정적으로 컴파일 된 비 동적 언어의 가장 큰 리팩토링 이점은 메소드에 대한 모든 호출이 어디 있는지 알고 있기 때문에 매우 복잡한 리팩토링을 수행 할 수있는 리팩터링 도구를 작성할 수 있다는 것입니다. 나는 IntelliJ IDEA을 매우 부러워합니다.

+1

"API는 단순히 함수 시그니처 이상입니다."... 시그니처를 변경하지 않고 메서드의 의미를 변경하면 메서드의 이름을 변경할 수 있습니다. 그러면 컴파일러가 도움을 받거나 모든 곳을 찾도록 요구합니다. 이전 이름을 사용하고 이전 의미를 기대하는 나머지 프로그램에서. – ChrisW