Статическая / строгая типизация и рефакторинг - PullRequest
6 голосов
/ 19 мая 2009

Мне кажется, что самым бесценным в статическом / строго типизированном языке программирования является то, что он помогает рефакторингу: если / когда вы меняете какой-либо API, компилятор сообщит вам, что это изменение сломало.

Я могу себе представить написание кода на языке выполнения / слабо типизированном языке ... но я не могу представить себе рефакторинг без помощи компилятора, и я не могу представить написание десятков тысяч строк кода без рефакторинга.

Это правда?

Ответы [ 5 ]

13 голосов
/ 19 мая 2009

Я думаю, вы смешиваете, когда типы проверяются с тем, как они проверяются. Время выполнения не обязательно слабое.

Основным преимуществом статических типов является именно то, что вы говорите: они исчерпывающие. Вы можете быть уверены, что все сайты вызовов соответствуют типу, просто позволяя компилятору делать свое дело.

Основным ограничением статических типов является то, что они ограничены в ограничениях, которые они могут выражать. Это зависит от языка: большинство языков имеют относительно простые системы типов (c, java), а другие - с чрезвычайно мощными системами типов (haskell, cayenne).

Из-за этого ограничения сами по себе не являются достаточными. Например, в java-типах более или менее ограничены проверки совпадения имен типов. Это означает, что значение любого проверяемого ограничения должно быть закодировано в какой-либо схеме именования, отсюда и множество косвенных указателей и общей схемы, общей для Java-кода. C ++ немного лучше в том, что шаблоны позволяют немного больше выразительности, но не приближаются к тому, что вы можете делать с зависимыми типами. Я не уверен, каковы недостатки более мощных систем типов, хотя очевидно, что некоторые или более людей будут использовать их в промышленности.

Даже если вы используете статическую типизацию, скорее всего, она недостаточно выразительна, чтобы проверять все, что вам нужно, поэтому вам также придется писать тесты. Вопрос о том, экономит ли вам статическая типография больше усилий, чем требуется, - это спор, который бушует целую вечность, и я не думаю, что он может дать простой ответ для всех ситуаций.

Что касается вашего второго вопроса:

Как мы можем безопасно перефакторизовать язык ввода во время выполнения?

Ответ - тесты. Ваши тесты должны охватывать все случаи, которые имеют значение. Инструменты могут помочь вам оценить, насколько исчерпывающими являются ваши тесты. Инструменты проверки покрытия позволяют узнать, охвачены ли тесты строки кода или нет. Инструменты тестовой мутации (шут, хекл) могут дать вам знать, если ваши тесты логически неполны. Приемочные тесты позволяют узнать, что написанное соответствует требованиям, и, наконец, регрессионные тесты и тесты производительности гарантируют, что каждая новая версия продукта поддерживает качество последней.

Одной из замечательных особенностей правильного тестирования на месте по сравнению со сложными указаниями типов является то, что отладка становится намного проще. При запуске тестов вы получаете конкретные ошибочные утверждения внутри тестов, которые четко выражают то, что они делают, а не тупые операторские сообщения об ошибках (например, ошибки шаблона c ++).

Независимо от того, какие инструменты вы используете: написание кода, в котором вы уверены, потребует усилий. Скорее всего, это потребует написания множества тестов. Если штраф за ошибки составляет очень , например, для аэрокосмического или медицинского программного обеспечения, вам может потребоваться использовать формальные математические методы для доказательства поведения вашего программного обеспечения, что делает такую ​​разработку чрезвычайно дорогой.

5 голосов
/ 19 мая 2009

Я полностью согласен с вашим мнением. Именно гибкость, с которой динамически типизированные языки должны быть хороши, на самом деле делает код очень сложным в обслуживании. В самом деле, существует ли такая вещь, как программа, которая продолжает работать, если типы данных изменяются нетривиальным образом без фактического изменения кода?

В то же время вы можете проверить тип передаваемой переменной и каким-то образом потерпеть неудачу, если это не ожидаемый тип. Вам все равно придется запускать свой код для устранения этих случаев, но по крайней мере что-то скажет вам.

Я думаю, что внутренние инструменты Google на самом деле выполняют компиляцию и, возможно, проверку типов в своем Javascript. Хотел бы я иметь эти инструменты.

2 голосов
/ 20 мая 2009

Для начала, я родной программист на Perl, поэтому, с одной стороны, я никогда не программировал с помощью сети статических типов. OTOH Я никогда не программировал с ними, поэтому я не могу говорить об их преимуществах. То, что я могу говорить, это то, на что это похоже на рефакторинг.

Я не считаю недостаток статических типов проблемой рефакторинга. Проблема в том, что у меня отсутствует рефакторинг браузера . У динамических языков есть проблема в том, что вы на самом деле не знаете, что на самом деле собирается делать код, пока вы на самом деле не запустите его. У Perl это больше, чем у большинства. У Perl есть дополнительная проблема с очень сложным, почти не разбираемым синтаксисом. Результат: нет инструментов рефакторинга (хотя они очень быстро работают над этим ). Конечный результат - я должен выполнить рефакторинг вручную. И это то, что вносит ошибки.

У меня есть тесты, чтобы поймать их ... обычно. Я часто оказываюсь перед дымящейся кучей непроверенного и почти непроверяемого кода с проблемой «курица / яйцо», заключающейся в необходимости рефакторинга кода для его тестирования, но необходимости его тестирования для его рефакторинга. Ик. К этому моменту я должен написать какой-то очень тупой, высокий уровень: «Программа выводит то же, что и раньше», вроде тестов, просто чтобы убедиться, что я что-то не сломал.

Статические типы, как предусмотрено в Java, C ++ или C #, действительно решают только небольшой класс задач программирования. Они гарантируют, что вашим интерфейсам передаются биты данных с правильной меткой. Но только то, что вы получаете коллекцию, не означает, что коллекция содержит данные, которые, по вашему мнению, содержат. Потому что вы получаете целое число, не означает, что вы получили правильное целое число. Ваш метод принимает объект User, но входит ли пользователь в систему?

Классический пример: public static double sqrt(double a) - это подпись для функции квадратного корня Java . Квадратный корень не работает на отрицательных числах. Где это написано в подписи? Это не так. Еще хуже, где говорится, что эта функция вообще делает? Подпись только говорит, какие типы он принимает и что возвращает. Он ничего не говорит о том, что происходит между ними, и именно там живет интересный код. Некоторые люди пытались получить полный API, используя дизайн по контракту , который можно широко описать как встраивание во время выполнения входных, выходных и побочных эффектов вашей функции (или их отсутствия) ... но это еще одно шоу.

API - это гораздо больше, чем просто сигнатуры функций (если бы это было не так, вам не понадобилась бы вся эта описательная проза в Javadocs), а рефакторинг - это гораздо больше, чем просто изменение API.

Самым большим преимуществом рефакторинга, которое дает статически типизированный, статически скомпилированный, не динамический язык, является возможность написания инструментов рефакторинга для выполнения довольно сложных рефакторингов за вас, поскольку он знает, где находятся все вызовы ваших методов. Я очень завидую IntelliJ IDEA .

1 голос
/ 19 мая 2009

Одним из преимуществ использования var в C # 3.0 является то, что вы можете часто менять тип, не нарушая никакого кода. Тип должен по-прежнему выглядеть одинаково - должны существовать свойства с одинаковыми именами, методы с одинаковой или сходной сигнатурой должны существовать. Но вы действительно можете перейти на совершенно другой тип, даже не используя что-то вроде ReSharper.

1 голос
/ 19 мая 2009

Я бы сказал, что рефакторинг выходит за рамки того, что компилятор может проверять даже в статически типизированных языках. Рефакторинг - это просто изменение внутренней структуры программ без влияния на внешнее поведение. Даже в динамических языках есть вещи, которые вы можете ожидать и проверять, вы просто теряете немного помощи от компилятора.

...