Type Wars
Дмитрий БахтенковЭта статья является переводом записи в блоге Роберта Мартина, автора таких книг, как Чистая Архитектура, Чистый код и др.
Ссылка на статью: https://blog.cleancoder.com/uncle-bob/2016/05/01/TypeWars.html
Ссылка на блог: https://blog.cleancoder.com/uncle-bob
_____________________
Первое мая, 2016 г
Мой сын Джастин и я начали новую серию видео для cleancoders.com исследование разработки мобильных приложений с использованием языка программирования Swift. Изучение Swift было интересным опытом. Язык очень продуман в отношении безопасности типов. Действительно, я не помню, чтобы я использовал язык, который был бы настолько усерден в отношении типов.
Например, тот факт, что переменная типа X также может быть null, означает, что вы должны объявить эту переменную для хранения “необязательного” значения с помощью ? [например, myVariable: X?]. Язык жестко ограничивает то, как используется это необязательное значение. Например, вы не можете ссылаться на него без проверки на ноль с помощью if или утверждения с помощью ! , которое указывает компилятору, что это не null. [например, myVariable!.myFunc()]
Экстремальный характер системы типов в Swift заставил меня задуматься о “Войнах типов”, которые наша индустрия вела в течение последних шести десятилетий. И это навело меня на мысль, что я должен вести блог об истории этих войн, а затем предсказывать будущие результаты. Итак, начнём.
ВНИМАНИЕ: В этой истории много упущений и содержится много неточностей.
Проблема типов на самом деле предшествует компьютерам. Во второй половине девятнадцатого века немецкий математик Готлоб Фреге разработал логическую систему, с помощью которой он надеялся вывести всю математику из первых принципов. Его работа была прародителем исчисления предикатов, но в ней был обнаружен критический недостаток. Накануне публикации британский филосов и математик Бертран Рассел написал Фреге и указал, что логическая система Фреге допускает двусмысленные утверждения – ни ложные, ни истинные. Фреге был опустошен и включил следующее замечание в приложение к своей работе.
“Вряд ли что-то более прискорбное может случиться с научным писателем, чем то, что один из фундаментов его здания пошатнется после завершения работы. Именно в такое положение меня поставило письмо мистера Бертрана Рассела, как раз когда печать этого тома приближалась к завершению”.
Одним из решений, которое было предложено для решения этой проблемы, было понятие типов. Была надежда, что если типы параметров в логических утверждениях Фреге могут быть ограничены, то двусмысленности Рассела могут быть устранены. Но в 1931 году эти надежды были разбиты теоремами о неполноте австрийского математика Курта Геделя.
Это был математический мир, в котором активно работал Алан Тьюринг. Он и другие математики, такие как Джон Фон Нейман и Джон Бэкхус, которые были глубоко погружены в эти проблемы, также были ответственны за многие основополагающие концепции информатики и наши первые языки, такие как, например, Fortran.
Впервые я столкнулся с концепцией типов в 1966 году, когда изучал Fortran в подростковом возрасте. Моему отцу удалось приобрести несколько очень ранних руководств по таким языкам, как Fortran, Cobol и PL/1; и я поглощал их. (Хотя у меня не было доступа к компьютеру!)
В Fortran было, по сути, два типа. Фиксированная точка (целое число) и плавающая точка. Тип обозначался первой буквой переменной. Переменные, которые начинались с букв от I до N (первые две буквы в слове “целое число”), были с фиксированной точкой. Все остальные переменные были с плавающей запятой.
Выражения в фортране не могли “смешивать типы”. У вас не могло быть целых чисел рядом с числами с плавающей запятой. Только определенные библиотечные функции могли переводиться между режимами.
Будучи молодым программистом, не имея доступа к компьютеру, я находил это очень запутанным. Я задавался вопросом, почему такое различие, с такими ужасающими ограничениями, было так важно. Только когда я выучил язык ассемблера, я начал понимать.
В первые годы моей работы программистом я немного писал на Fortran, Cobol и PL/1; но я был гораздо больше сосредоточен на ассемблере. Я чувствовал, что языки “высокого уровня” были раздутыми, медленными, отстающими. Настоящие программисты писали ассемблер – по крайней мере, я так думал. Но затем, в 1977 году, меня познакомили с Си.
Это была любовь с первого взгляда. Когда я сидел у костра на своем заднем дворе, читая копию Кернигана и Ричи, я приветствовал этот язык, который не был раздутым, медленным, копированием; но вместо этого был простым переводом ассемблера.
У C, конечно, были типы; но они никоим образом не применялись. Вы можете объявить функцию, которая принимает значение int, но затем передать ей значение с плавающей точкой, символ или двойник. Языку было все равно. Он с радостью поместил бы переданный аргумент в стек, а затем вызвал бы функцию. Функция с радостью выбросила бы свои аргументы из стека, исходя из предположения, что они были объявленным типом. Если вы неправильно набрали типы, у вас будет авария. Просто. Любой программист на языке ассемблера мгновенно понял бы это и избежал бы этого.
В конце 70-х годов я впервые осознал, что идет война. Война о типах. Хотя я был полностью очарован C, я знал о другом претенденте на мое внимание: Pascal. Паскаль был всем, что я ненавидел в языках высокого уровня. Я считал, что это было раздутое, медленное отступление. Люди, которые программировали на этом языке, не были настоящими программистами, потому что они зависели от языка, чтобы обеспечить их безопасность. Видите ли, Паскаль был строго типизирован.
В Pascal, если вы объявили функцию, которая принимает определенные типы аргументов, вам нужно было вызвать эту функцию с этими типами. Язык обеспечивает безопасность типов. Для такого программиста на языке ассемблера, как я, в мои двадцать с небольшим, это было слишком сложно. Я чувствовал, что Паскаль-это язык для младенцев.
Очевидно, многие программисты согласились со мной, потому что C выиграл эту языковую войну, и выиграл ее решительно. Начало 80-х годов было расцветом C. По мере распространения мини-компьютеров, распространялся и язык C. Паскаль выжил, но только потому, что Apple решила (ошибочно) использовать его в качестве языка для Macintosh – решение, которое в конечном итоге будет отменено.
Время от времени появлялись и другие языки, но их не воспринимали слишком серьезно. Мы слышали о Smalltalk и машинах стоимостью в миллион долларов, необходимых для его запуска. Мы знали о Logo, Lisp и нескольких других языках. Но в моей части мира мы были счастливы с Си и не могли представить ничего лучшего.
Objective-С появился примерно в 1986 году или около того. Я помню, как довольно серьезно смотрел на странный маленький гибрид Брэда Кокса между C и Smalltalk. Но именно C++ привлек мое внимание, потому что после большей части десятилетия двойственного отношения C к типам я был готов к языку, обеспечивающему строгую типизацию.
Видите ли, я усвоил свой урок. По мере того как программы становились все более сложными в конце 70-х и начале 80-х годов, проблема сохранения правильности ваших типов начала выходить из-под контроля. Было слишком много раз, когда я отлаживал проблемы в полевых условиях, только для того, чтобы обнаружить, что кто-то вызвал функцию с параметром long, которая была объявлена как принимающая значение int.
Поэтому, когда Страуступ опубликовал свою книгу по C++, я был готов! (Я также был рад, что это производная от C, так что мне не пришлось признаваться Паскалю Уини, что они были правы с самого начала)
Маятник качнулся. Индустрия приняла C++, и началась эра строгой типизации. Мы, программисты C, закаленные в боях и уставшие от войны, поклялись, что никогда не вернемся к беззаботным дням неисполненных типов.
Тем временем программисты Smalltalk чесали в затылках, гадая, в чем же тут дело. Видите ли, их язык также был строго типизирован; но их типы были неявными. В Smalltalk типы примененялись во время выполнения. Ошибки ввода в Smalltalk не приводили к неопределенному поведению, как это было в C. Поведение в Smalltalk было очень четко определено. Вы получили исключение типа во время выполнения.
Мы в сообществе C++ считали, что это просто то же самое, что разыменование нулевого указателя. В конце концов, кого волнует, что программное обеспечение в ракете выйдет из строя из-за исключения типа или ошибки сегментации? В любом случае, ракета выходит из строя.
Конец 80-х и начало 90-х годов были своего рода “холодной войной” между статической проверкой типов C++ и динамической проверкой типов Smalltalk. Другие языки росли и падали в течение этого времени; но эти две широкие категории хорошо определяли их.
Потом война снова разгорелась. Но на этот раз на улицах были не просто программисты с табличками на языках Си и Паскаль. На этот раз это была настоящая война с игроками-тяжеловесами. Это была война между IBM и Sun.
Но чтобы подготовить почву, я должен рассказать вам об исследовании, проведенном американским специалистом Кейперсом-Джонсом относительно продуктивности программистов, использующих разные языки. Его исследование показало, что программисты на Smalltalk были гораздо более продуктивными, чем программисты на C++. Некоторые люди думали, что разница составляет целых 5 раз. Другие думали, что это больше похоже на 2X-3X. Но никто не думал, что программисты на C++ более продуктивны, чем программисты на Smalltalk.
В свете этого IBM выбрала Smalltalk в качестве языка разработки для Интернета. Они сделали огромную ставку на это, разработав IDE, фреймворки и всю необходимую инфраструктуру. Sun, с другой стороны, поддерживала Java (которая была просто облегченной C++).
Битва бушевала. Но решающим фактором были типы. Sun выставляла ранг за рангом программистов Java (урожденных C++) и выиграла эту битву над IBM на основе безопасности типов (аргумент о ракетах). В тот день Smalltalk умер как язык. (Но не волнуйтесь, программисты на Smalltalk им отомстили.)
Итак, Java и его двоюродный брат-ублюдок C# стали языками Интернета и господствовали в течение двух десятилетий. Но за кулисами многое происходило.
Видите ли, программисты Smalltalk решили проблему с ракетами своим собственным уникальным способом. Они изобрели дисциплину. Сегодня мы называем эту дисциплину TDD (Test Driven Development).
Используя TDD, программисты Smalltalk были уверены, что ракета достигнет своей цели. На самом деле, у них было гораздо больше уверенности, чем могла обеспечить проверка типов компилятора C++ или Java. Поэтому, когда Smalltalk умер, пятая колонна программистов Smalltalk проникла в ряды Java-программистов и начала обучать TDD. Их цель: диверсия.
Видите ли, когда Java-программист привыкает к TDD, он начинает задавать себе очень важный вопрос: “Почему я трачу время на удовлетворение ограничений типа Java, когда мои модульные тесты уже все проверяют?” Эти программисты начинают понимать, что они могли бы стать намного более продуктивными, перейдя на динамически типизированный язык, такой как Ruby или Python.
И это именно то, что произошло во второй половине первого десятилетия нынешнего тысячелетия. Тонны Java-программистов прыгнули с корабля и стали преданными языкам с динамической типизацией. Этот скачок с корабля продолжается и по сей день, подстегиваемый тем фактом, что зарплаты программистов, работающих на динамических языках, как правило, выше.
О, и я должен рассказать вам об одном специальном подразделении программистов Smalltalk, которые остались в IBM и планировали отомстить Sun. Они осуществили эту месть, создав … Eclipse.
И вот мы здесь. Маятник быстро качается в сторону динамической типизации. Программисты отказываются от статически типизированных языков, таких как C++, Java и C#, в пользу динамически типизированных языков, таких как Ruby и Python. И все же, появляющиеся новые языки, такие как go и swift, похоже, на стороне статической типизации. Итак, готовится ли сцена для следующей битвы?
Чем все это закончится?
Мое собственное предсказание состоит в том, что TDD является решающим фактором. Вам не нужна проверка статического типа, если у вас есть 100% покрытие модульными тестами. И, как мы неоднократно видели, охват модульными тестами, близкий к 100%, может быть достигнут и достигается. Более того, преимущества этого достижения огромны.
Поэтому я предсказываю, что по мере того, как TDD будет все больше восприниматься как необходимая профессиональная дисциплина, динамические языки станут предпочтительными языками. Программисты Smalltalk, в конце концов, победят.
Это говорит старый программист на C++.
___________________
С вами был Flex Code