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

Преимущества

Отличная навигация

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

  • Точные предложения автозаполнения делают возможным обнаружение, исследование и руководство. Нет необходимости открывать документацию по API в отдельном окне браузера или просматривать исходный код, чтобы узнать, как использовать элемент. При вводе символа точки после элемента-получателя появляется небольшое окно со всеми доступными методами, полями и, иногда, настраиваемыми действиями. Вся эта информация точна, зависит от контекста и, следовательно, умна. Сканируя записи во всплывающем окне с их подписями и встроенной документацией, можно быстро получить представление о возможностях получателя и его предполагаемом использовании. Можно предположить, существует ли определенная возможность, набрав предполагаемое имя. И всплывающее окно отвечает сразу. Возможности этой функции невозможно переоценить.
  • Точный «Поиск использования» позволяет исследовать и понимать. Исходя из личного опыта, наиболее многообещающий подход к пониманию роли элемента (например, класса или функции) - это выяснить, как он используется остальной частью кода. Применение к элементу функции «Найти использование» - наиболее эффективный способ достижения этой цели. Процесс может быть повторен методом «поиска в глубину», чтобы понять роль других связанных элементов. Таким образом, можно относительно быстро понять всю подсистему.
  • Точный «Перейти к определению» позволяет исследовать и понимать. «Перейти к определению» - это двойное слово «Поиск использования». Если вы заинтересованы в реализации элемента или просто хотите понять окружающий его контекст, «Перейти к определению» неоценим, особенно для сторонних библиотек.

Предотвращение ошибок

Статическая типизация ограничивает набор синтаксически правильных программ. Для непосвященных это может показаться плохим - отнюдь не так. На практике это ограничение предотвращает множество ошибок, которые в противном случае проявились бы только в определенных ситуациях во время выполнения. У этих ошибок, как правило, есть досадная причуда, заключающаяся в том, что они создают «взрывы» далеко от корня проблемы. Отлаживать эти проблемы - ад.

Рефакторинг

При структурном изменении кода компилятор и IDE будут указывать все сайты использования, которые необходимо адаптировать. Во многих более простых случаях, например при переименовании класса, IDE автоматически адаптирует остальную часть кода за вас. Если инструментарий заставляет вас чувствовать себя уверенно при рефакторинге, вы сделаете больше. И это хорошо.

Самостоятельная документация

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

Иллюстрация

Рассмотрим следующий фрагмент кода.

function f(p) {
  //...
}

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

Теперь некоторые популярные языки с нестатической типизацией имеют или будут вводить необязательные аннотации типов. Отлично! Однако культурная проблема написания «прерываемого» кода остается в значительной степени. Рассмотрим следующий метод из гипотетической библиотеки AWS S3.

// Expects accessKeyId to be specified in config
function createS3Client(config: Object | Map<String, String>) { 
  // ...
}

Даже с аннотациями типов: если нет ощущения возможности использования инструментов - потому что среда не поощряет это, - сами аннотации - это капля в море. Комментарий также нельзя использовать с помощью инструментов. Что делать, если вы неправильно написали accessKeyId как accesKeyId? Что, если библиотека затем неявно получит идентификатор ключа доступа, который вы установили в качестве переменной среды, но забыли? Все может работать локально. Тем не менее, вы можете наблюдать сбой в производстве. В статически типизированной среде больше ценится инструментарий. По крайней мере, разрешенные ключи конфигурации обычно должны быть перечислены синтаксически. Вместе с поддержкой со стороны IDE вы бы сразу заметили свою ошибку.

Заключение

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

Дальнейшее чтение

Вот список существенных ссылок, разделяющих похожие взгляды.

Дальнейшие примечания

Этот раздел не является обязательным и содержит дополнительные мысли.

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

Широко распространено представление о том, что статическая типизация в первую очередь заключается в том, чтобы делать ошибки невозможными, а не в инструментах. Уменьшение количества ошибок - это очень приятный побочный эффект статической типизации, равно как и повышение эффективности сгенерированного кода, но это не главная его привлекательность для прагматичного программиста. Причина в том, что существует множество классов ошибок, которые типичная система типов не улавливает. Это также не может помешать вам ошибиться в рассуждении. Можно разработать систему статического типа, которая позволит вам кодировать гораздо больше свойств вашей программы: См., Например, Зависимая типизация. В цене сильно снижена эргономика программирования.

Статическую типизацию можно скорее рассматривать как средство создания неявных связей между синтаксическими элементами явными и, следовательно, доступными для обнаружения без необходимости запуска программы. Эти ссылки можно выбрать с помощью таких инструментов, как IDE, и они приведут к преимуществам, упомянутым в этой статье.

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

Можно привести аргумент, что, в конце концов, хороший программист может написать хороший код в любой среде, а плохой программист может написать плохой код в любой среде. Хотя в определенном смысле этот аргумент верен, он, похоже, является способом прекратить обсуждение. Система статического типа и хороший инструментарий не могут помешать кому-то умышленно обойти ее. Но, по крайней мере, это может помочь программисту найти лучшее решение. Хороший программист может написать хороший код в любой среде, но он наверняка напишет еще лучший код в лучшей среде.

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

Если вы исследуете Интернет в поисках видеороликов и обсуждений создателей Dart и Kotlin в период с 2012 по 2015 год, вы найдете множество аргументов, аналогичных приведенным в этой статье. Дарт получил много критики за выбор системы без звука (для особого случая с дженериками). Некоторые даже предположили, что поэтому система типов совершенно бесполезна. Создатели подчеркнули, что это абсолютно не так.

Java - очень инструментальный язык. Он не только в принципе пригоден для использования в качестве инструментов, но и на самом деле имеет отличные инструменты, например, в виде Intellij IDEA. Есть много очевидных, но есть и более тонких причин. Первичная из них - это система статических типов Java вместе с ее структурированной системой обозначений. Нельзя игнорировать популярность Java в том смысле, что без нее было бы нецелесообразно вкладывать все эти усилия в ее инструментарий. Конечно, Java - не особо привлекательный язык. К счастью, существуют альтернативные языки JVM, такие как Kotlin, которые повторно используют экосистему и инструменты Java, но при этом являются значительным улучшением по сравнению с языком Java.

Есть веские аргументы против статической типизации. Это тема для отдельной статьи.

Ниже приведены дополнительные ссылки / источники с интересными точками зрения.