Почему некоторые сеньоры не любят Python.
UniLecsИ почему они защищают статические языки, такие как C++
![](/file/97dff2c17d74fdbc71d95.jpg)
В моей предыдущей статье о самых медленных современных языках программирования мы разобрались, насколько языки с динамической типизацией, такие как Python, удобны для пользователя и менее подвержены ошибкам со стороны разработчика.
Оказывается, с этим согласны не все. Многие senior разработчики утверждают, что для них работа с динамически типизированными языками — это головная боль. Комментарий ниже собрал много лайков:
«Простите, что? Языки с динамической типизацией менее подвержены ошибкам, чем языки со статической типизацией? Извините, но проработав 21 год программистом я в это не поверю». — Расмус Шульц
После этого ответа я решил собрать основные причины, по которым senior разработчики недолюбливают языки с динамической типизацией, и изложить эти причины в данной статье.
В качестве примера языка программирования с динамической типизацией мы возьмем Python.
Динамическая типизация
Есть множество разных типизаций(strong typing, duck typing), однако в этой статье мы ограничимся лишь двумя наиболее популярными: динамической и статической.
Динамическая типизация — это когда тип данных определяется во время выполнения программы. То есть нет необходимости явно объявлять типы данных. Примером языков с динамической типизацией могут стать Python, Ruby или JavaScript.
В отличие от динамической типизации, статическая типизация предполагает явное объявление типа данных перед компиляцией. Пример: C/C++ или Java.
Как и во многих жизненных вещах, тонкость языков программирования состоит в том, что некоторые из их преимуществ являются также недостатками. Динамическая типизация была создана с целью упрощения процесса разработки. Тем не менее этот функционал таит в себе большую ловушку.
Давайте рассмотрим пример кода на Python:
![](/file/1ee686491190959faa1b7.png)
Результат:
[12, 12, 12, 12]
В приведенном выше примере мы хотим выполнить некие арифметические операции с переменной max_number и сохранить результаты в списке my_list. Однако переменная max_number не изменилась и my_list хранит ошибочные результаты.
Это все потому, что внутри цикла for мы сделали ошибку в названии max_number, что привело к созданию другой переменной с именем max_numbre. Смешно, правда? Да вот не очень. Такие ошибки может допустить любой человек, особенно под конец рабочего дня. Отыскать её в коде порой бывает очень сложно и утомительно.
То ли дело если рассматриваем языки со статической типизацией, такие как С/C++, то в них вы должны объявить переменные перед их использованием. Вам также необходимо провести предварительный анализ, дабы убедиться, что типы ваших переменных согласованы. В конечном счете вы выиграете с точки зрения безопасности, так как будете лучше контролировать свои переменные.
Важность статической типизации хорошо описана в разговоре 2009 года с тремя разработчиками Twitter. В нем они рассказывают, почему компания решила начать использовать Scala,- язык со статической типизацией.
Глобальная блокировка интерпретатора (GIL — the global interpreter lock)
Еще один подводный камень — это производительность. На это особенно обращают внимание senior разработчики.
Сеньорам, в отличие от джуниоров, которые обычно ограничиваются несколькими десятками строк кода, часто приходится работать с кодом, который состоит из сотен или тысяч строк. Следовательно, они уделяют особенное внимание производительности языка программирования.
GIL(the global interpreter lock) является узким местом производительности для таких языков программирования, как Python и MRI Ruby. Ресурсы, которые блокирует GIL, — это потоки(thread с англ.) ЦП.
В то же время, языки программирования, у которых нет GIL, полностью используют мощность процессора. Таким образом, они поддерживают параллельные вычисления.
Параллельные вычисления — это не что иное, как одновременное выполнение потоков. Этот тип вычислений сейчас актуален как никогда из-за астрономического объема данных, которые необходимо обрабатывать.
Пример параллельных вычислений — на диаграмме ниже:
![](/file/9e4a5d020bd12203be2ed.png)
Разумно предположить, что при одинаковой тактовой частоте процессора: чем больше ядер имеет ваш компьютер, тем быстрее работают программы. Однако наличие GIL положит конец параллельным вычислениям.
GIL — это блокировка, которая позволяет исполняться только одному потоку. Выбор потока на исполнение осуществляется в порядке очереди. Это означает, что пока поток с наивысшим приоритетом исполняется, другие потоки переводятся в состояние ожидания, пока выполняющийся поток не отдаст GIL. И еще ко всему этому, пользователь не может контролировать выбор потока. За ранжирование приоритета потоков отвечает операционная система.
Как все происходит на самом деле, лучше всего иллюстрирует диаграмма:
![](/file/9d294be7b7fb54e216bc4.png)
Пытаясь решить проблему производительности, многие программисты или, по крайней мере, смышленые программисты пытаются вручную разбить код по потокам, используя, например, модуль многопоточности в Python. Но в результате такой код демонстрирует еще худшую производительность. Хотя такой результат может показаться странным, но это всего лишь computer science и не более. Если вникнуть в дело, все должно встать на свои места.
Хотя основная часть Python разработчиков прекрасно осведомлена об этой проблеме, трудно избавиться от GIL, потому что GIL — это основа многих особенностей Python таких, как управление памятью.
Гвидо ван Россум, автор Python, сказал, что не уверен, что Python когда-либо будет поддерживать параллельные вычисления, ибо это не было предусмотрено на начальном этапе проектирования.
В то же время статически типизированные языки, такие как С/C++ не имеют GIL’а. Это делает их более производительными.
Чувствительность к whitespaces
Программировать на языке, который помечает ошибку на основании неуместных или отсутствующих пробелов, для некоторых затруднительно. Whitespaces — это пробел, табуляция, новая строка, возврат каретки(\r). В отличие, например, от C, Python чувствителен к пробелам.
Продемонстрируем это с помощью следующего сравнения C кода и Python.
Python версия:
![](/file/b03eb40c38657a5245174.png)
Результат:
![](/file/86c7b8d1a73560f88752f.png)
C версия:
![](/file/522091eb3087a135db8df.png)
Результат:
![](/file/a34cc6d439aaa8aa02b1b.png)
В отличие от C версии, которая справилась с беспорядочной структурой кода и вывела правильный результат, Python сгенерировал синтаксическую ошибку, которая была вызвана неправильным выражением. Таким образом, можно сказать, что Python не такой надежный, как C++ или чистый C.
Но, честно говоря, если вы разрабатываете на С, то старайтесь не экспериментировать с отступами и табуляцией, придерживайтесь определенных code style.
По иронии судьбы, в то время как многие программисты утверждают, что чувствительность к пробелам раздражает, Python разработчики считают, что иметь дело с проблемами намного лучше, чем выполнять поиск столбцов в конце.
Наконец, проблемы с чувствительностью к пробелам раздражают при работе с большими блоками кода. Тем не менее, если в вашей команде прививаются хорошие практики программирования, проблемы с чувствительностью к пробелам можно легко преодолеть.
Обратная совместимость
Отсутствие поддержки обратной совместимости означает, что старые версии Python кода могут не работать с более новыми версиями. Другими словами, необходимо найти синтаксические изменения, которые произошли в новой версии, и соответствующим образом переписать код.
Хороший пример, когда обратная совместимость оказалась серьезной проблемой, — это переход с Python 2 на 3.
Команда разработчиков ядра Python предполагала, что людям не составит труда преобразовать код Python 2 в Python 3. Они ошиблись.
Сам автор Python признал это, когда сказал:
«Мы недооценили количество людей, которые написали большой объем кода на Python, а затем практически забыли, как он работает. Таким образом, у них не было возможности обновить его. Мы поняли, что у нас в этой части проблема».
Решением этой проблемы стало продление поддержки Python 2.7.
Заключение
Языки программирования всегда были спорной темой, поэтому нельзя считать что-то правильным или неправильным. По крайней мере, всегда есть несколько причин предпочесть один язык другому. Как правило, каждый язык программирования подходит определенной группе людей. Автор Python сказал:
«Научиться программировать на Python намного проще, чем на Java или Swift. Java и Swift — отличные языки программирования для профессиональных разработчиков программного обеспечения. Но Python можно преподавать детям в средней школе».
Кроме того, наилучшим сценарием было бы наличие языка программирования, который мог бы сочетать достоинства C++ и Python.
В настоящее время наиболее близким прототипом является язык программирования Julia.