[Перевод] Python без типов: таким он когда-то был
О типизации в Python сказано уже очень много. Если вам выпало сомнительное удовольствие поработать со мной, то вы, вероятно, в курсе, насколько скептически я отношусь к типизации в Python. Причины тому — сложность синтаксиса, mypy еле ползает, реализация языка в принципе переусложнена, а взаимодействовать с ним зачастую неудобно. Сегодня я не буду упирать на эти детали, а хочу пригласить вас в небольшое путешествие в прошлое и рассказать, каковы были мои первые впечатления от работы с Python. Почему? Потому что я думаю, что существует фундаментальный и глубокий конфликт между формообразующей философией Python и концепцией типизации. Причём, этот конфликт не нов.
Концепция типизированных языков программирования появилась задолго до 2015 года. Дебаты по поводу необходимости типизировать код — также совсем не новое явление. Всякий раз, когда вы собираетесь начать новый софтверный проект, особенно такой, что напоминает веб-сервис, у вас на выбор всегда будет несколько языков программирования. Ещё в 2004 году, когда я только начинал знакомиться с программированием, такой выбор уже был широк. Вариантом номер один считался не Python, и даже не PHP, а Java. Java де-факто применялась в любых серьёзных проектах по программированию веб-приложений, поскольку обладала как системой типов, так и возможностями enterprise-класса. PHP считался игрушкой, а Python было не сыскать. PHP был популярен, но в близких мне кругах всегда воспринимался как смехотворный проект. Идея, что кто-нибудь попробует создать бизнес на основе PHP, казалась ещё смешнее. Помню, на первом курсе в моём окружении было принято считать, что в реальном мире все проекты работают на .NET, Java и C++. PHP высмеивался, Python и Ruby практически не обсуждали, а доля JavaScript на сервере была несущественной.
В таких условиях я и существовал, писал на PHP и Python. Выбор мой был продиктован не отвращением к статической типизации (или ленью), а тем, насколько исключительно удобны эти языки для разработки — в основном именно потому, что в них нет типов. Работать с ними было одно удовольствие. Да, у меня в распоряжении не было интеллектуальных подсказок, но любые изменения, которые я вносил, мгновенно отображались на сайте. Помню, как напрямую подправлял работающие сайты в режиме реального времени по FTP. Позже редактировал веб-страницы прямо в редакторе vim, развёрнутом на продакшен-сервере. Думаете, это было страшно или ужасно? Ещё как! Но, чёрт возьми, продуктивно. Работа в таком режиме многому меня научила. Например, ценному искусству идти на компромисс. Причём, не только мне, но и целому поколению программистов, работавших с этими языками, довелось узнать, что в нашей величайшей слабости (этот код не типизировался и не компилировался) заключена наша величайшая сила. Да, она налагает некоторые ограничения и требует немного иного подхода к программированию, зато такой метод невероятно продуктивен.
Существовал мир XPath, мир DTD, были миры SOAP и WSDL. Был такой мир, где системы обладали такой огромной неотъемлемой сложностью, что при работе было никак не обойтись без IDE, генерации кода и инструментария для работы во время компиляции. Совсем в другом мире жил я. В моём мире я сидел с Vim, CVS и SVN, а также с компьютером, на котором была базовая комплектация Linux. При помощи этих инструментов мне удавалось создавать вещи, которыми я очень гордился. В конце концов я перешёл с PHP на Python, так как последний предлагал компромиссы, которые меня более устраивали. Но я никогда не забуду о том, что мне дал PHP: работая с ним, я осознал, что код не должен быть идеально вылизан, главное, чтобы он решал поставленные задачи. А он решал.
Но, точно, как и при работе с PHP, общая площадь контакта между мной и средой выполнения Python оставалась крошечной. Я писал код, интерпретатор, преобразовывал его в инструкции байт-кода (я в этот байт-код даже мог посмотреть!), после чего код выполнялся в крошечном цикле в рамках интерпретатора. Интерпретатор был опенсорсным, его было легко читать и, самое главное, я мог там покопаться. Такой подход к работе не только помог мне лучше разобраться в компьютерах; более того, я невероятно легко мог понять, что именно в коде происходит. Несомненно, мне было полностью понятно всё происходящее между тем кодом, который я написал, и тот код, который работает в программе от начала и до конца.
Да, там не было статической проверки типов, и интеллектуальных подсказок тоже в принципе не существовали. Такие компании как Microsoft тогда даже не считали Python за язык. Но, чёрт возьми, насколько он был продуктивен! Мало того, на нём пишутся крупные программные проекты. Было понятно, где какие компромиссы нужны. В продакшене налево и направо летали ошибки, поскольку то и дело передавались ненадлежащие типы, но у нас был инструментарий, позволявший работать в такой ситуации. Явственно припоминаю коллегу, специалиста по .NET, насколько он был поражён, когда я похвастался перед ним тем арсеналом, которым располагаю. Ведь если бы я развернул плохой код, и этим кодом кому-нибудь прилетело бы в лицо, то в ответ я получил бы электронное сообщение, в котором приводился бы не только совершенно разборчивый стектрейс, но и строка исходного кода для фреймов. Тем более мой собеседник поразился, когда я показал ему модуль, при помощи которого можно было удалённо подключаться к действующему интерпретатору и на лету выполнять код Python, требующий отладки. Вся работа программиста выстраивалась вокруг такой «луковицы», слоёв в которой было совсем не много.
Но позвольте я отмечу: ведь все аргументы против динамических языков и динамических систем типизации тогда уже были известны! Никто ничего нового не изобретал, ничего особенно не изменилось. Все мы знали, что типизация — ценная штука, и в один голос говорили: да на что она нам! Прекрасно обходимся утиной типизацией. Пусть она будет нашим козырем.
Вот что изменилось: теперь разработчикам уже нет такого доверия, как раньше, и в программирование повторно проникает та сложность, с которой мы боролись. Современный Python порой бывает просто непостижим для разработчика. Можно сказать, в некоторых областях мы изобретаем новую Java. Мы превратились в тех, кого когда-то вытеснили. Просто мы потеряли бдительность и вступили на путь, который может привести нас к наихудшему аналогу Java. Мы внедрили типизацию в язык, который её не поддерживает, наш интерпретатор медленный, у него есть GIL (глобальная блокировка интерпретатора). Нужно действовать внимательно и не забывать, где наши корни. Не следует коллективно отказываться от тех благ, которые у нас были.
Сегодня ветер переменился, это невозможно отрицать. Другие языки показали, что типизация может быть ценна в самых новых и потрясающих отношениях. Когда мне доводилось спорить с разными людьми о том, как устроена типизация в Python по сравнению с типизацией в Java, в языке Java ещё даже не было дженериков, а JavaScript боролся с собственной репутацией «невыносимой игрушки». До создания TypeScript оставались ещё годы. Ничего нового не изобреталось, но некоторые вещи популяризовались. Например, абстрактные типы данных вошли в практику, а когда-то были просто исследовательскими игрушками. В .NET начали смешивать статическую и динамическую типизацию. Позже в TypeScript популяризовали практику добавления типов в те языки, которые исходно создавались без них. В нашем сообществе тем более хватает разработчиков, которые вообще не представляют, чем были привлекательны такие языки.
К чему же мы пришли? Мне просто захотелось поворчать о том, что раньше трава была зеленее, а теперь повсюду эти ужасные типы? Едва ли. Невозможно отрицать, что типизация полезна, и в ней есть зерно, которое в целом помогает сильно повысить производительность труда. Но от компромиссов при этом никуда не уйти, и выбор «я за типизацию» или «я против типизации» не должен стигматизироваться. Ключевые принципы остаются прежними: типы ценны, но за пользование ими приходится платить.
________________________________________________________________________________
Постскриптум: Python сейчас на том этапе развития, когда усилия по его типизации не приносят мне никакой пользы. Если мне нужно повысить продуктивность, то я склоняюсь к использованию TypeScript. Возможно, Python выйдет на тот уровень, где сейчас находится TypeScript. Тогда я вернусь к этому вопросу.