Преимущества динамических языков в реальной жизни? - PullRequest
23 голосов
/ 25 июня 2009

Я изучаю несколько возможностей для разработки новой системы (веб-приложения).

Я "старомодный" парень, объектно-ориентированный в природе (преобразованный из процедурного много лет назад). Я играл с Python и немного изучил Ruby, но, честно говоря, меня привлекло использование инструментов Microsoft (C #, ASP.NET MVC). Вся эта типизация во время выполнения, отсутствие ошибок компилятора в базовых вещах и т. Д. Просто усложняет мою жизнь, когда дело доходит до создания больших сложных приложений.

Я постоянно слышу, как люди говорят о замечательных вещах, которые вы можете делать с динамическими языками, но кроме примеров с собаками, кошками и того, как быстро вы можете кодировать классный способ подсчета вещей, просто кажется, что «индустриальная сила» Visual Studio чтобы устранить эти изящные мелочи, которые предлагают динамические языки, особенно теперь, когда у вас есть бесплатные экспресс-версии VS и полные версии, доступные бесплатно для стартапов.

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

Ответы [ 9 ]

19 голосов
/ 25 июня 2009

«как быстро вы можете кодировать» настолько меня беспокоит, что я с радостью отказался от длинного, медленного утомления, заставляя вещи компилироваться.

Преимущества динамических языков.

  1. Нет компиляции, нет сборки. Просто код и тест с последующим развертыванием в производство.

  2. Немедленное удовлетворение. Не нужно тратить время на то, чтобы разобраться в том, каким может быть вызов API. Просто введите его в интерактивном режиме в приглашении Python >>> и посмотрите, что он на самом деле делает .

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

  4. Меньше кода. Динамический язык самоанализ уменьшает громкость источника. Я не пишу это в своих приложениях; Я полагаюсь на рамки, чтобы сделать это для меня. Но основанный на фреймворке код часто очень короткий; нет повторяющихся объявлений, которые так распространены в Java, где вы должны повторять вещи в конфигурации XML.

  5. Никаких загадок. Как мы говорим в сообществе Python: «Используй источник, Люк». Нет никакой двусмысленности в том, что делает фреймворк или что на самом деле означает API.

  6. Абсолютная гибкость. Поскольку наши требования меняются, нам не приходится бороться с разрушительными изменениями, которые нарушают всю архитектуру. Мы можем - тривиально - внести изменения в несколько классов, потому что Python Duck Typing избавляет от необходимости модифицировать отсутствующие определения интерфейса там, где мы не думали, что они будут необходимы. Их просто нет; код, который мы не написали, - это код, который мы не должны исправлять или поддерживать.

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

  8. Поскольку источник является приложением, источником может быть его собственный файл конфигурации. У нас нет файлов конфигурации XML или INI в каком-то внешнем синтаксисе. У нас есть файлы конфигурации в Python. Фреймворк Django делает это, и мы следуем их примеру. У нас есть очень сложные макетные декларации данных для демонстрации продаж и модульного тестирования. Суперсложные данные на самом деле представляют собой набор объектов Python, которые поступили бы из базы данных, за исключением того, что мы не загружали базу данных. Проще просто настроить конструктор объекта Python вместо загрузки базы данных SQL.

[BTW. После 30 с лишним лет разработки программного обеспечения на Cobol, Fortran, PL / I, Java, C, C ++ я просто устал от относительно низкоуровневой оптимизации рук, которая требуется большинству компилируемых языков. Несколько лет назад я прочитал комментарий о неэффективности большинства компиляторов: он побуждает нас создавать сложные системы сборки, чтобы обойти ограничения компилятора. Нам нужен только make, потому что cc такой медленный.]


Редактировать

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

Если вы хотите написать много кода на основе неправильно понятого API, тогда может помочь динамический язык. Вы можете написать много кода, который аварийно завершает работу на одном языке: C #, VB, C ++, Java или Python. Вы всегда можете написать код, который не будет работать.

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

Python может заранее предупредить вас, что код не будет работать. Как правило, вы не можете заставить его работать в интерактивном режиме. Тем не менее, вы все равно можете написать много кода, который не проходит все юнит-тесты.

6 голосов
/ 25 июня 2009

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

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

Система типов Common Lisp хороша для этого. Все объекты данных знают свой тип, и вы можете явно указать этот тип, если хотите.

Модель исполнения с циклом eval позволяет очень легко тестировать подпрограммы по мере их написания. Вам не нужно явно писать тесты заранее (хотя ничто не мешает вам сделать это); вы можете написать их и выполнить на лету (а затем вы можете превратить их в набор тестов - думайте об этом как о разработке дополнительных тестов).

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

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

5 голосов
/ 25 июня 2009

В целом, я предпочитаю говорить об «интерактивных» языках, а не о «динамических» языках. Когда у вас есть только цикл редактирования / компиляции / запуска, любой оборот занимает много времени. Ну хотя бы по порядку «нужно сохранить, скомпилировать, проверить отчет о компиляции, запустить тест, проверить результаты теста».

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

3 голосов
/ 25 июня 2009

Вот части моего ответа на предыдущий аналогичный вопрос ( Я знаю C #. Буду ли я более продуктивно работать с Python? ):

Я сам из C # / .NET. Начал программировать в .NET в ок. 2001, и примерно в то же время был представлен Python. В 2001 году мое время, проведенное в C # по сравнению с Python, составило около 90% C # / 10% Python. Теперь соотношение составляет 5% C # / 95% Python. В моей компании мы все еще поддерживаем линейку продуктов на основе .NET. Но все новое основано на Python.

Мы создали нетривиальные приложения на Python.

По моему опыту, что делает меня более продуктивным в Python против C #, это:

  • Это динамический язык. Использование динамического языка часто позволяет удалить целые архитектурные слои из вашего приложения. Динамическая природа Pythons позволяет создавать многократно используемые абстракции высокого уровня более естественным и гибким (по синтаксису) способом, чем в C #.
  • Библиотека. Стандартные библиотеки и множество библиотек с открытым исходным кодом, предоставляемых сообществом, отличаются высоким качеством. Диапазон приложений, для которых используется Python, означает, что диапазон библиотек широк.
  • Ускоренный цикл разработки. Отсутствие шага компиляции означает, что я могу тестировать изменения быстрее. Например, при разработке веб-приложения сервер dev обнаруживает изменения и перезагружает приложение при сохранении файлов. Запуск модульного теста из моего редактора - всего лишь нажатие клавиши, и он выполняется мгновенно.
  • «Простой доступ» к часто используемым функциям: списки, списки, генераторы, кортежи и т. Д.
  • Меньше многословного синтаксиса. Вы можете создать веб-каркас Python на основе WSGI с меньшим количеством строк кода, чем ваш обычный файл .NET web.config: -)
  • Хорошая документация. Хорошие книги.
2 голосов
/ 25 июня 2009

Интерактивные оболочки! Это огромный прирост производительности. Просто запустите irb / python, чтобы сидеть перед интерактивной оболочкой (для рубина и питона соответственно). Затем вы можете в интерактивном режиме протестировать свои классы, функции, поэкспериментировать с выражениями (отлично подходит для регулярных выражений), различным синтаксисом и алгоритмами. Это настоящая площадка для программистов и отличный инструмент для отладки.

Только я два цента об ошибках:

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

Обнаруживаемые компилятором ошибки - это те ошибки, которые вы будете обнаруживать при выполнении различных автоматических тестов (модульных, функциональных и т. Д.), И те, которые вы должны написать в любом случае. Вероятно, Линус Торвальдс может сказать: Регрессионное тестирование? «Что это? ему. И, используя интерактивные оболочки, вы получаете автоматическую обратную связь о вашем синтаксисе, например, когда вы компилируете приложение, но код выполняется на месте.

1 голос
/ 07 сентября 2016

Мой опыт

Я работал с обоими, вероятно, около десяти лет с каждым профессионально, всего.

Я анекдотично потратил далеко больше времени, пытаясь заставить статически типизированные языки понять, что я хочу сделать (возможно, недели - возможно, месяцы в целом), чем я потратил на исправление ошибок, вызванных ошибками динамического типа (возможно час или два в год?).

Исследования

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

Тоталитарный

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

Системы статического типа могут заставить вас думать о полезных вещах. Это особенно верно в таких языках, как Haskell с классами типов и монадами (которые, признаюсь, до сих пор не совсем понятны). Это хорошо, но я считаю, что тоталитарно полагать, что это всегда хорошо. Вы должны подумать об этом, когда это уместно. Язык не должен заставлять вас думать об этом или осознавать его с самого начала развития.

Слишком ограничительный и недостаточно ограничительный

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

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

Boilerplate

Статически типизированные языки, кажется, поощряют шаблон или генерацию кода. Я не уверен, если это присуще. Возможно, достаточно мощная система макросов преодолеет это. Я сравниваю состояние макетов для тестирования в Swift с состоянием цели c.

Монолитная

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

Напротив, в интерактивных вычислительных средах вы не создаете новое приложение, а вместо этого расширяете систему, чтобы она делала больше. Системы, которые я знаю (машины Lisp, Smalltalk и Unix - их инструменты имеют динамически типизированный интерфейс между ними), используют динамическую типизацию для сборки деталей.

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

Скорость

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

Долгосрочный

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

1 голос
/ 25 июня 2009

Мне тоже нравится статическая типизация. Но я не нахожу, что я так сильно скучаю, когда пишу на Python (если используемые мной классы хорошо документированы - и я бы сказал, что никакая языковая функция никогда не спасет нас от плохой документации) , Также я не скучаю по большинству динамических возможностей Python при написании C ++ (лямбды, я скучаю: привожу C ++ 0x, даже если синтаксис ужасен. И перечислим понимания).

Для обнаружения ошибок большинство ошибок "неправильный тип передан" и "неправильный метод, называемый" не являются тонкими, поэтому основное отличие состоит в том, что исключения заменяют ошибки компилятора. Вы должны убедиться, что вы действительно выполняете каждый путь к коду и все важные пути к данным, но, конечно, вы делаете это в любом случае для серьезных проектов. Я подозреваю, что редко бывает трудно проверить все классы, которые могут быть назначены данной переменной. Основная проблема заключается в том, что люди, привыкшие к C ++, научились опираться на компилятор и не стараются избегать больших классов ошибок, которые компилятор поймает. В Python у вас есть возможность подумать об этом во время написания кода или дождаться запуска тестов, чтобы узнать об этом. Аналогично, операция «автоматического рефакторинга» в C ++ «измените параметры и посмотрите, что не скомпилируется», требует некоторой модификации в Python, если вы хотите найти все сайты вызовов.

Поэтому вам необходимо убедиться, что вы выполняете правильное подмножество тестов, так как полный модульный тест большого приложения Python займет гораздо больше времени, чем допустимо на этапе «компиляции» вашего текущего кода C ++ / компиляции / код / ​​компиляция / код / ​​компиляция / цикл тестирования. Но это та же проблема, что и нежелание перестраивать все в C ++.

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

Кроме того, стоит помнить, что многие ошибки и предупреждения компилятора C ++ на самом деле не относятся к вашему дизайну, а к тому, что существует так много разных способов написания кода, который выглядит правильно, но ведет себя совершенно неправильно. Программисты Python не нуждаются в предупреждении, что они случайно вставили триграф или набрали указатель типа, потому что у них нет психотического препроцессора или оптимизаций, основанных на строгом алиасинге.

0 голосов
/ 31 декабря 2014

Я знаю, что это было давно, но принятый ответ перечисляет свойства, которые не ограничиваются языками с динамической типизацией. Например, # 4 (меньше кода) также верно для Scala (если я правильно помню). Это определенно верно для Groovy (который построен на основе Java, поэтому технически Groovy является и статическим, и динамическим). Единственное, с чем я согласен - это # ​​7 (устойчивость)

Из википедии,

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

По моему опыту, преимущества динамических языков заключаются в меньшем количестве кода / более эффективном коде и лучших "лучших" практиках (например, в культуре строгого тестирования) ... вещах, которые не относятся к динамическим языкам.

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

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

0 голосов
/ 25 июня 2009

Рассмотрим случай, когда у вас есть подпрограмма, которая принимает один аргумент:

sub calculate( Int $x ){ ... }

Теперь ваши требования меняются, и вам приходится иметь дело с несколькими аргументами:

multi sub calculate( Int $x ){ ... }
multi sub calculate( Int @x ){
  my @ret;
  for @x -> $x {
    push @ret, calculate( $x );
  }
  return @ret;
}

Обратите внимание, что между разными версиями было очень мало изменений.

А что если вы узнали, что действительно должны были использовать числа с плавающей запятой:

multi sub calculate( Num $x ){ ... }
multi sub calculate( Num @x ){
  my @ret;
  for @x -> $x {
    push @ret, calculate( $x );
  }
  return @ret;
}

Это было меньшее изменение, чем раньше, и обратите внимание, что любой фрагмент кода, который вызывает эти подпрограммы, продолжит работать без единого изменения.

Эти примеры были написаны в Perl6

...