Почему динамические языки программирования создают трудности при сопровождении больших объемов кода
Евгений Брикман — ведущий разработчик Play Framework для LinkedIn сказал в видео-презентации, записанной на JaxConf 2013, что большие кодовые базы труднее поддерживать, если они написаны на динамических языках.
На одном из Q&A сайтов был задан этот вопрос, и лучший ответ на него дал пользователь Эрик Липперт.
Итак, его ответ.
Предупреждение: я не смотрел презентацию.
Я работал в проектных комитетах по JavaScript (очень динамический язык), C # (в основном статический язык), и Visual Basic (который как статический, так и динамический), у меня есть несколько мыслей по данному вопросу.
Начнем с того, что трудно поддерживать большую кодовую базу, и точка. Большой объем кода очень трудно написать, несмотря на то, какие инструменты есть в вашем распоряжении. Ваш вопрос не означает, что сопровождение большого кода в статически типизированных языках будет простым, а вопрос предполагает только то, что вы встретите больше проблем, если будете поддерживать код в динамическом языке, а не в статическом.
Немного забегаю вперед. Мы должны четко определить, что мы понимаем под «динамическим» языком: под «динамическим» языком я имею в виду противоположное «статическому» языку.
Статически типизированный язык – это язык, разработанный для облегчения автоматической проверки правильности при помощи инструментов, которые имеют доступ только к исходному коду, а не к данным в рабочем состоянии программы. Те данные, что выводятся с помощью средств называют типами. Разработчики языка создают набор правил, которые делают программу типобезопасной, и средства пытаются проверить, что программа следует этим правилам.
Динамически типизированный язык
в отличие от статического не облегчен такого рода проверкой. Значения данных, хранящихся в любом конкретном месте, могут быть определены только путем проверки во время работы программы.Мы могли бы привести различия между динамической областью видимости и лексически ограниченными языками, но давайте не будем отходить от целей данного обсуждения. Динамически типизированный язык не должен быть с динамической областью видимости и статически типизированный язык не должен быть лексически ограничен, однако часто присутствует взаимосвязь между ними.
Так как у нас есть конкретные условия вопроса, давайте прямо поговорим о больших кодовых базах. Большие кодовые базы, как правило, имеют некоторые общие характеристики.
Все эти характеристики создают препятствия на пути к пониманию кода, и, следовательно, создают препятствия для правильного изменения кода. Короче говоря: время = деньги и сделать правильные изменения в массивном коде дорого из-за характера этих проблем.
Также бюджет конечен, и мы хотим сделать столько, сколько можем, с ресурсами, которые имеем. Люди, которые сопровождают крупные кодовые базы стремятся снизить стоимость при помощи принятия правильных решений для смягчения этих препятствий. Некоторые способы для преодоления проблем:
- Модульность: код разделен на модули, где каждый модуль имеет четкую задачу. Логика кода может быть задокументирована и понятна без того, чтобы пользователю нужно было понимать подробности его реализации.
- Инкапсуляция: в модулях проведены различия между их «внешней» поверхностью и их «внутренними» деталями реализации, таким образом, что последние могут быть улучшены без ущерба для правильности работы программы в целом.
- Повторное использование: когда проблема решена правильно один раз, она решается так всегда. Результат может быть повторно использован в решении других проблем. Такие технологии, как создание библиотеки полезных функций, или создание функциональности базового класса, которые могут быть расширены с помощью производного класса, или архитектуры, в которой приветствуется содержимое, состоящее из методов, реализованных повторным использованием кода. И все это для того, чтобы снизить затраты.
- Аннотации: аннотированный код описывает допустимые значения, которые могут принимать переменные.
- Автоматическое обнаружение ошибок: команде, которая работает над большой программой, имеет смысл создать приспособление, которое сразу определит ошибку и расскажет о ней, чтобы она была решена быстро. Такие технологии, как написание набора тестов, использование статического анализатора попадают в эту категорию.
Статически типизированный язык является примером последнего. Вы получаете прямо в самом компиляторе возможность увидеть ошибки связанные с типами данных, и компилятор сообщит об этом. Явно типизированный язык требует, чтобы в местах объявления переменных, были примечания, несущие информацию о том, что может содержаться в этих переменных.
Таким образом, по одной только этой причине, в динамически типизированных языках труднее сопровождать объемную кодовую базу, потому что работу, которая выполняется компилятором «бесплатно», вы должны делать в виде написания набора тестов. Если вы хотите комментировать свои переменные, то вы должны продумать четкую систему, и если новый член вашей команды случайно нарушит ее, то вы должны найти нарушение как можно раньше.
Теперь я бы хотел упомянуть ключевой момент: есть сильная взаимосвязь между динамической типизированностью языка и нехваткой возможностей, которые могли бы снизить расходы на содержание, и этот ключевой момент — причина, почему труднее поддерживать большой код в динамическом языке. И такая же взаимосвязь есть между статической типизированностью и наличием средств, которые делают программирование легче.
Давайте возьмем JavaScript в качестве примера. (Я работал на оригинальных версиях JScript в Microsoft с 1996 по 2001 год) цель проекта заключалась в том, чтобы обезьяна танцевала, при наведении на нее курсором. Скрипты зачастую состояли из одной строки. Мы рассматривали десятистрочные скрипты, и было довольно неплохо, скрипты из сотни строк уже считались большими, а скрипты из тысячи строк были неслыханно огромными.
JavaScript был специально разработан для программ, которые велики настолько, чтобы один человек мог видеть все это на одной странице, так же JavaScript не только динамически типизирован, но так же в нем присутствует мало средств, которые помогают программировать большие кодовые базы:
- Нет модульной системы, нет классов, интерфейсов, или даже пространств имён. Эти элементы есть в других языках, чтобы помогать организовывать объемные кодовые базы.
- Система наследования, а так же наследование прототипов развиты довольно слабо. И не понятно, как правильно строить глубокие иерархии (вроде: капитан вид пирата, пират вид человека, человек вид чего-то там…) в out-of-the-box JavaScript.
- Нет инкапсуляции: каждое свойство каждого объекта может изменяться по желанию какой-либо части программы.
- Там нет никакого способа, чтобы обозначить какое-либо ограничение по памяти: любая переменная может содержать любое значение. Но это не просто недостаток тех самых возможностей, которые облегчают программирование. Есть также функции, которые делают его более трудным.
- Система управления ошибок в JavaScript разработана с предположением, что скрипт выполняется на веб-странице, и что цена ошибки невелика, и что пользователь, который увидит неточности скорее всего не будет способен их исправить. Поэтому, как бы много ошибок ни было, программа попытается выполниться до конца. Это разумно, для данных целей языка, но она, безусловно, делает программирование больших объемов кода в разы сложнее, потому что это увеличивает сложность написания тестов. Зачастую искать ошибки в таких программах труднее, чем писать тесты, которые их выявят.
- Код может изменить сам себя на основе данных с пользовательского ввода через объекты, такие как Eval или при помощи добавления новых блоков сценариев в DOM динамически. Любые инструменты статического анализа не могут даже знать, что код сделает с программой!
- И так далее.
Ясно, что возможно преодолеть все эти препятствия и создать большую программу в JavaScript. В настоящее время существует много программ JavaScript состоящих из миллионов строк. Но большие команды, которые сопровождают эти сложные проекты используют различные инструменты и у них присутствует строгая дисциплина, чтобы преодолевать препятствия, которые JavaScript бросает на вашем пути:
- Они пишут тест-кейсы для каждого идентификатора использующегося в программе. В мире, где орфографических ошибки игнорируются, это необходимо. Это экономически выгодно.
- Пишут код в типизированных языках, таких как TypeScript, и компилируют как JavaScript.
- Они используют фреймворки, которые способствуют программированию в стиле, который лучше поддается анализу, более склонен к модульности и менее вероятно воспроизведет на свет наиболее распространенные ошибки.
- У них хорошая дисциплина в именовании, в разделении обязанностей, и так далее. Опять же, это снижает стоимость, и все эти задачи будут выполнены компилятором в типичном статически типизированном языке.
В заключение скажу, что далеко не только динамичный характер типизации увеличивает расходы на содержание большого кода. Это конечно приводит к повышению затрат, но это далеко не все. К примеру, я мог бы спроектировать вам язык, который был бы динамически типизирован, но имел бы и пространство имен, и модули, и наследование, и библиотеки, и закрытые данные, и так далее, и кстати говоря, C# 4 является подобным языком. Он достаточно динамичен и очень удобен в программировании больших кодовых баз.
Чаще всего то, что часто отсутствует в динамических языках, в результате и повышает расходы в сопровождении больших программ. Динамические языки, которые включают в себя средства для хорошего тестирования модульности, повторного использования, инкапсуляции и так далее, на самом деле могут существенно снизить затраты при программировании больших кодовых баз, но многие часто используемые динамические языки не имеют эти полезные приспособления. Кто-то должен их создать, и это увеличит затраты.
Перевод статьи «Why do dynamic languages make it difficult to maintain large codebases?»
Язык динамического программирования — frwiki.wiki
- В этой статье обсуждается класс языков программирования. Для метода, заключающегося в сокращении времени выполнения алгоритма, см. Динамическое программирование.
Термин динамический язык программирования используется в информатике для описания класса языков высокого уровня, которые выполняют действия во время выполнения, которые другие языки могут выполнять только во время компиляции . Эти действия могут включать в себя расширение программы, добавление нового кода расширения структуры данных, и изменение типа системы в то время как программа работает. Такое поведение можно эмулировать практически на любом языке достаточной сложности, но динамические языки не имеют препятствий, таких как статическая типизация, препятствующих непосредственному получению такого поведения.
Концепции динамических языков и динамической типизации не идентичны , и динамический язык не обязательно является динамически типизированным, хотя большинство динамических языков таковыми являются.
Резюме
- 1 Ограничения и неоднозначность определения
- 2 Расположение
- 2.1 Динамическое вычисление выражения
- 2.1.1 Функции высшего порядка
- 2.2 Изменение объектов во время выполнения
- 2.3 Функциональное программирование
- 2.3.1 Лексические замыкания
- 2.3.2 Продолжение
- 2.4 Отражение
- 2.5 Макросы
- 2.1 Динамическое вычисление выражения
- 3 динамических языка
- 4 Примечания и ссылки
- 5 См. Также
- 5.1 Связанные статьи
- 5.2 Внешние ссылки
Ограничения и неоднозначность определения
Определение динамического языка неоднозначно, потому что оно стирает различие между кодом и данными, как между компиляцией и средой выполнения . В виртуальных машинах, тем время компиляция, и способность многих языков на некоторых системах динамически изменять код машины делают это различие устаревшими. В общем, утверждение о том, что язык является динамическим, является скорее заявлением о простоте использования динамических функций, чем заявлением о других внутренних возможностях языка.
Имплантация
Есть несколько механизмов, тесно связанных с концепцией динамического программирования. Ни один из них не является важным для классификации языка как динамического, но многие из них доступны на самых разных этих языках.
Динамическая оценка выражения
В языке программирования Lisp появился термин Eval, обозначающий оценку выражения. В этом языке Eval — это термин, введенный в язык Lisp и обозначающий оценку инструкций, то есть акт выполнения инструкций, представленных структурами данных, называемыми S-выражениями . В современном смысле eval обозначает механизм выполнения всех видов инструкций, таких как исходный код или данные, которые не являются машинным кодом.
Оценка исходного кода новой программы используется во многих языках, которые, в отличие от Lisp, проводят различие между чтением исходного кода и его преобразованием во внутреннюю форму, а затем преобразованием внутренней формы в действие, которое должно быть выполнен. Эти языки часто называют « интерпретируемыми языками », когда стандартным средством выполнения программы является eval.
Функции высшего порядка
Но Эрик Мейер и Питер Дрейтон предупреждают, что любой язык, способный загружать исполняемый код во время выполнения, может так или иначе оцениваться, даже если этот код находится в форме разделяемых библиотек в машинном коде. Они предполагают, что функции высшего порядка воплощают истинный смысл динамического программирования и что другие языки используются в качестве временной замены для поддержки истинных функций высшего порядка. «
Изменение объектов во время выполнения
В динамическом языке можно динамически изменять систему объектов или типов. Это означает создание новых объектов из определения, доступного во время выполнения, или на основе смеси нескольких типов или объектов. Это также может означать изменение дерева наследования и, таким образом, изменить способ поведения существующих типов, в частности, в отношении вызова методов .
Функциональное программирование
Концепции функционального программирования являются особенностью многих функциональных языков и происходят от Лиспа .
Лексические замыкания
Лексическое замыкание является одним из наиболее часто используемых понятий функционального программирования. Он позволяет вам создать новый экземпляр функции, сохраняющий контекст, в котором она была создана. Простым примером является создание функции для сканирования текста слова:
function new_scanner (word) temp_function = function (input) scan_for_text (input, word) end function return temp_function end function
Обратите внимание, что внутренняя функция не имеет имени и хранится в переменной temp_function
. Каждый раз при new_scanner
выполнении он возвращает новую функцию, которая запоминает значение параметра word
, переданного при его установке.
Лексические замыкания — одна из важнейших концепций функционального программирования, и многие языки поддерживают, по крайней мере, эту степень функционального программирования.
Продолжение
Некоторые динамические языки используют понятие продолжения . Продолжение представляет состояние выполнения, которое можно повторно вызвать. Например, синтаксический анализатор может вернуть промежуточный результат и продолжение, которое при повторном вызове может продолжить синтаксический анализ записи. Продолжения могут очень сложным образом взаимодействовать с областью видимости, особенно в том, что касается лексических замыканий. По этой причине многие динамические языки не предоставляют продолжения.
Отражение
Отражение присутствует во многих языках динамических. Обычно это включает в себя самоанализ, то есть анализ типов и метаданных. Он также включает оценку и модификацию программы как данных, например, функциональность, предоставляемую Lisp для анализа S-выражений, это ходатайство .
Макросы
Ограниченное количество динамических языков обеспечивает функциональность, которая объединяет самоанализ и оценку кода в функциональность, называемую макросом . Большинство программистов сегодня знакомы с макросами C или C ++, которые являются статической функцией.
Они вызывают только подстановку строк в тексте программы перед ее компиляцией. Но в динамических языках макросы предоставляют доступ к внутренней работе компилятора и полный доступ к интерпретатору, виртуальной машине или среде выполнения, позволяя определять расширения языка, которые могут оптимизировать сгенерированный код или изменять синтаксис языка. В Лиспе мы говорим о гигиеническом макросе, чтобы отличать эти макросы от макросов, заменяющих компиляцию, таких как текст.
Динамические языки
|
|
|
|
Ассемблере, то C, то C ++, ранние версии Java и Fortran не являются динамическими языками программирования.
Примечания и ссылки
- ↑ [PDF] Эрик Мейер и Питер Дрейтон, « Статический набор текста там, где это возможно, динамический набор текста, когда это необходимо: конец холодной войны между языками программирования », Microsoft Corporation,
- ↑ См пример их использования P.330 из Larry Wall «s Programming Perl ( ISBN 0-596-00027-8 )
- (fr) Эта статья частично или полностью взята из статьи в Википедии на английском языке под названием « язык динамического программирования » ( см. список авторов ) .
Смотрите также
Статьи по Теме
- Язык сценария
Внешние ссылки
- (ru) « Динамические языки» — готовность к следующим испытаниям, по замыслу, Дэвид Ашер, доктор философии; ActiveState, 27 июля 2004 г.
<img src=»//fr.wikipedia.org/wiki/Special:CentralAutoLogin/start?type=1×1″ alt=»» title=»»>
Динамические языки — Javatpoint
В области программирования много изобретений, каждый год вводится множество языков программирования. Каждый раз программисты вводят новый язык, который должен исправить некоторые проблемы, возникшие с предыдущим. Некоторые считают, что все языки программирования одинаковы и используют стандартное программное обеспечение и язык программирования. Но почему программисты каждый год изобретают новые программы? В качестве примера рассмотрим java, он введен для исправления некоторых проблем с C++. Динамические языки были созданы таким образом, чтобы решать некоторые проблемы лучше, чем существующие языки. Общепринятого определения динамических языков не существует. Мы можем определить, что любой язык программирования, допускающий модификацию во время выполнения, является динамическим языком. Модификация во время выполнения — это не что иное, как изменение программы во время ее работы. Исходное определение также включало необходимость того, чтобы язык был высокоуровневым, динамически типизированным и с открытым исходным кодом. Наиболее востребованными динамическими языками являются Python, Perl и Ruby. Динамические языки позволяют программистам изменять даже структуру во время работы. Это известно как модификация во время выполнения. Язык высокого уровня — это не что иное, как язык с более высоким уровнем абстракции. C является языком высокого уровня, потому что он имеет более высокий уровень абстракции. Python и другие динамические языки имеют другой уровень абстракции. Функции, ожидаемые от динамических языков, включают автоматизацию, управление памятью и обработку исключений, более абстрактные встроенные типы данных, такие как списки и словари, механизмы нестатической типизации и специальные варианты синтаксиса для улучшения читаемости кода и значительного снижения его многословности. Динамические языки разрабатываются исходя из предположения о наличии некоторых предопределенных компонентов для простого создания приложений. Динамические языки часто интерпретируются, а не компилируются. Это означает, что исходный код читается во время выполнения интерпретатором — компьютерной программой, которая переводит исходный код в целевое представление, которое он немедленно выполняет и оценивает. Этот процесс противоположен компиляции, при которой компилятор читает исходный код, а язык, использующий динамическую типизацию, считается языком с динамической проверкой, поскольку проверка типов происходит во время выполнения (во время выполнения), а не во время компиляции, как это происходит с статическая типизация. Проверка типов состоит из проверки того, что код учитывает ограничения типов, предотвращающие применение операций к объектам несовместимых типов. Если язык не требует, чтобы тип переменной был известен во время компиляции, то говорят, что язык имеет динамическую типизацию. Некоторые из самых популярных языков динамического программирования:
Самые популярные динамические языки были разработаны для решения технических проблем, с которыми столкнулись их изобретатели, и, как правило, по-прежнему ориентированы на решение технических проблем, а не на то, чтобы быть инструментами для продвижения корпоративной повестки дня. Эти языки построены на Философия оптимизации времени человека вместо времени компьютера — они жертвуют эффективностью ради повышения производительности. Сама разработка этих языков значительно отличается от традиционной модели разработки языков программирования, это настолько глубоко открытый исходный код, что существует почти полная прозрачность того, как язык развивался благодаря записям отслеживания ошибок, журналам программного обеспечения контроля версий и обсуждениям в списки рассылки. Все это публично. Еще одна особенность процесса разработки заключается в том, что ядро языка развивается отдельно от библиотек. Ядро контролируется небольшой командой людей, которые обеспечивают язык. Использование динамических языков:
|
Динамический язык программирования — Academic Kids
From Academic Kids
вводятся или удаляются, могут создаваться новые классы объектов, могут появляться новые модули. В качестве побочного эффекта этого динамизма большинство динамических языков программирования имеют динамическую типизацию, что сторонники статической типизации считают недостатком (см. Также статическую типизацию). Однако, по мнению сторонников динамических языков программирования, гибкость динамических языков компенсирует эти недостатки и даже дает столь значительные преимущества, что делает это важным свойством, например, для интерактивного программирования. Более поздние исследователи утверждают, что с немного большим количеством накладных расходов и синтаксиса возможно и выгодно сочетать статическую типизацию с динамическими функциями для достижения интерактивности, а также обеспечивая преимущества безопасности и производительности строго типизированного языка.
Обычно программирование состоит из написания вместе битов компьютерного кода, известного как функций, которые работают с данными. Эти функции физически представлены компьютерным кодом в некотором месте памяти. В большинстве языков программирования вызовы функций в исходном коде заменены инструкциями по запуску кода в этом физическом местоположении (точное место определяется компоновщиком). Одна из проблем с этим подходом заключается в том, что он не позволяет модифицировать код после его компиляции. Например, если в коде обнаружена ошибка, единственным решением является исправление исходного кода и перекомпиляция приложения.
Динамические языки полагаются на адреса функций, которые ищутся во время выполнения, вместо того, чтобы компилироваться в адреса во время компиляции. Это позволяет изменять символы, чтобы они указывали на новые функции, позволяя изменять определения. Многие динамические языки также выполняют поиск данных таким же образом, позволяя модифицировать «статические» объекты, такие как классы.
Однако это вводит поиск во время выполнения, поскольку каждый вызов функции требует поиска символа, а затем указателя функции. По этой причине динамические языки часто работают медленнее, чем нединамические, что является еще одним «поцелуем смерти» в 19 веке.90-е. На практике эту задержку можно значительно сократить почти до нуля, однако, например, язык программирования Objective-C использовал предварительно загруженный кэш и небольшой фрагмент кода на ассемблере, чтобы сократить эти накладные расходы до одной операции.
Степень динамичности зависит от языка. Objective-C был основан на компиляторе GNU / GCC и допускал динамизм только вызовов функций (называемых категоризацией по несвязанным причинам) путем перезаписи кода отправки метода.