В программировании очень много вещей, в которых я разбираюсь очень плохо. Настолько много, что меня иногда спрашивают — а в чем ты вообще разбираешься?
Я разбираюсь в типах и проектировании удобного и надежного АПИ. Но для доброй половины разрабов эти вещи ничего не значат. Потому что они используют динамическую типизацию, и понятия не имеют, какие проблемы и зачем я решаю.
Большую часть жизни я просто махал на них рукой и проходил мимо. Эти глупцы не понимают очевидных вещей, и я не нанимался разъяснять каждому js-нику, почему его код — это не разработка, а игрушечное прототипирование. Но время идёт, а количество идиотов вокруг и не думает уменьшаться, вместо того, чтобы всей своей фронтенд индустрией переехать наконец на статический тайпскрипт, эти ослы начинают использовать всякие кложуры, писать тонны тестов, и идти на все мыслимые ухищрения — лишь бы не разбираться в типах.
В мире очень много спорных вещей, когда в зависимости от того, что ты хочешь получить, правда переваливается с одной чаши весов на другую, не оставляя место никакой абсолютной истине в последней инстанции. Пару лет назад я уже писал о типизации, но тогда я был молодой, глупый и трусливый — у меня была позиция, но чтобы не показаться идиотом, я старательно спрятал её за философскими рассуждениями о том, как все вокруг сложно, и как трудно работать адептам разных моделей типизации вместе.
Но сегодня я пришёл сюда, чтобы сказать:
Динамическая типизация — адское говнище, а инженеры которые верят в такой подход — серьезно ошибаются.
Смотрите. Статическая типизация — это такая штука, которая позволяет мне выразить часть условий, при которых код не сможет работать в виде дополнительных инструкций для компилятора. То есть я знаю, что вот эта функция работает только вот с такими объектами, я описываю их в ее сигнатуре и получаю гарантию — объект другого типа в функцию передан не будет. Кроме того, типы позволяют мне рассказать компилятору, как устроен мой код. Компилятор сможет использовать эту информацию, чтобы проводить оптимизации и, например, давать мне подсказки. Разные инструменты для разработки могут использовать информацию о типах, чтобы автоматически производить рефакторинг, делать это безопасно и с гарантией, что нихера не сломалось. Сам код типов делает кодовую базу понятной, и приближает твои наборы инструкций к процессам, которые ты описываешь этим кодом.
Противники статической типизации говорят, что все эти вещи не нужны. Они говорят мне, что
Баги, которые отлавливают типы, не стоят усилий, чтобы записать код этих типов.
Серьезно? Серьезно? Нам лень писать символы? Братан. Ты думаешь пять часов, а печатаешь десять минут. Ты инженер, так что попробуй посчитать, о каком эфорте ты говоришь. И не забудь, что со статической типизацией, или без нее, ты не раз в своей кодовой базе опишешь структуры объектов, с которыми будешь работать. Но если будешь пользоватся статикой, компилятор и IDE смогут делать эту работу за тебя. И проверять твой код на ошибки описания этих объектов. Если тебе лень писать аннотации типов к функциям — используй ЯП с выводом типов, или генерируй их с помощью расширений к IDE.
Если ты топишь, что аннотации раздувают кодовую базу — вспомни, блин, все наши принципы про то, что явное лучше неявного, что одна из важных задач кодовой базы — быть понятной и читаемой, как человеком, так и машиной. Если тебе лень проводить работу в своей тупой башке, что бы понять на каких типах будет работать твое приложение, то у меня для тебя плохие новости. Что бы написать что-то рабочее, тебе все равно придётся проделать эту работу. Просто делать ты это будешь не детерминировано, а по востребованию. В итоге ты опишешь процесс, но не уложишь его в своей голове, и качество твоего кода отреагирует. Багами, несвязностью и костылями.
Противники статической типизации говорят, что ранний отлов ошибок не так уж и важен.
Ало. Ваша доска с задачами набита багами, которые допустили разработчики. Чинить баги — большая часть всей работы в индустрии. Мы тратим миллиарды человекочасов, чтобы пофиксить до нелепости смешные ошибки. Вы пишите код без багов? или у вас только умные баги? Да хрен там плавал. Если бы компилятор не проверял за вас, что вы закрыли фигурную скобку, поверьте мне, у нас были бы сотни багов с незакрытой скобкой.
Когда думаешь о том, где баг потенциально может возникнуть, а где нет, появляется опасная иллюзия, что ты держишь ситуацию под контролем, и предусмотрел все кейсы. Я работаю семь лет, ещё ни разу не было такого, чтобы я предусмотрел все кейсы. Потому что это частный случай задачи коммивояжера — ты НИКОГДА не можешь предусмотреть все кейсы. Ты даже самые распространенные и вероятные рассмотреть не можешь. Когда, кто и в какой ситуации напишет код с критичным багом, в каком модуле и как он это сделает — ты, блин, понятия не имеешь. Все, что ты можешь сделать, это уменьшить шансы на появление бага. Вот и уменьшай, тебе за это платят бешеные деньги.
Противники статической типизации противопоставляют типы тестам.
Я не стану говорить, что они идиоты, я скажу, что они просто не подумали об этом хорошенько. Вот вам очевидная истина — тесты фиксируют, что существующий код работает по известным условиям. А типы гарантируют, что ещё не написанный код будет написан по известным условиям. Тесты нужны. Типы нужны. Ты все ещё уменьшаешь шансы, что все свалится. В мире, где у нас есть бюджет, чтобы пять часов обсуждать с командой, что не так в нашем эджайле, найдется время дописать аннотации и пару тестов.
Болваны из динамического мира говорят, что статическая типизация лишает код гибкости.
Я не понимаю, о какой гибкости они говорят. Даже в нищем C# система типов позволяет мне не иметь контроль над типами данных, чей тип не имеет для меня значения. Я всегда могу доказать языку, что вот, мол, слушай сюда, я не могу описать, что это за штука, но я точно знаю, что у нее есть вот такое поле, вот такого типа или вот такого типа. И я буду работать только с ним. Любой статически типизированный язык это позволяет. А гибкость и свобода писать код, который точно не сможет работать — такая гибкость мне не нужна.
JS-подростки говорят, что статическая типизация смещает акцент с задачи на описание типов.
А я говорю, что описание типов — и есть описание процесса, который ты автоматизируешь. В объектно-ориентированном программировании, в функциональном программировании, в любом другом программировании мы описываем вещи из реального мира, и наш код содержит те знания о них, без которых он не сможет работать. Ты все равно будешь проделывать эту работу.
Если система типов конкретного ЯПа не позволяет тебе описать свой домен правильно и защищено — это проблема конкретного языка, а не статической типизации в целом. Это нормально, и конкретно на этом языке ты местами используешь всякие object и dynamic, но везде где можешь получить гарантии — ты их получаешь.
Я писал код и с динамической типизацией, и со статической. Со строгой и нестрогой, со структурной и номинативной.
Только динамическая вызывала у меня стойкое ощущение, что я пишу детский псевдокод, который сработает, только если сойдутся звезды.
Динамическая типизация — это игрушка, штука, которая подойдет, когда ты решил закодить что-то в одного, и забыть об этом. Когда ты собрался вести разработку, когда с твоим кодом будут работать другие люди, когда код вылезет на прод и начнет решать проблемы пользователей, обновляясь раз в неделю — динамическая типизация абсолютно нахрен неприемлема. Просто запомни это и иди менять расширения своих файлов с .js на .ts.
И посмотри мой подкаст — там новый выпуск