На протяжении последних месяцев я использую Go для имплементаций Proof of Concept (прим.пер.: код для проверки работоспособности идеи) в свободное время, отчасти для изучения самого языка программирования. Программы сами по себе очень просты и не являются целью написания статьи, но сам опыт использования Go заслуживает того, чтобы сказать о нем пару слов. Go обещает быть (прим.пер.: статья написана в 2015) массовым языком для серьезного масштабируемого кода. Язык создан в Google, в котором активно им пользуются. Подведя черту, я искренне считаю, что дизайн языка Go плох для умных программистов. Go очень просто научиться, настолько просто, что введение заняло у меня один вечер, после чего уже мог продуктивно писать код. Книга по которой я изучал Go называется An Introduction to Programming in Go (перевод), она доступна в сети. Книгу, как и сам исходный код на Go, легко читать, в ней есть хорошие примеры кода, она содержит порядка 150 страниц, которые можно прочесть за раз. Сначала эта простота действует освежающе, особенно в мире программирования, полного переусложненных технологий. Но в итоге рано или поздно возникает мысль: "Так ли это на самом деле?" Google утверждает, что простота Go — это подкупающая черта, и язык предназначен для максимальной продуктивности в больших командах, но я сомневаюсь в этом. Есть фичи, которых либо недостает, либо они чрезмерно подробны. А все из-за отсутствия доверия к разработчикам, с предположением, что они не в состоянии сделать что-либо правильно. Это стремление к простоте было сознательным решением разработчиков языка и, для того, чтобы полностью понять для чего это было нужно, мы должны понять мотивацию разработчиков и чего они добивались в Go. Так для чего же он был создан таким простым? Вот пара цитат Роба Пайка (прим.пер.: один из соавторов языка Go): Что? Так Роб Пайк в сущности говорит, что разработчики в Google не столь хороши, потому они и создали язык для идиотов (прим.пер.: dumbed down), так чтобы они были в состоянии что-то сделать. Что за высокомерный взгляд на собственных коллег? Я всегда считал, что разработчики Google отобраны из самых ярких и лучших на Земле. Конечно они могут справиться с чем-то посложнее? Быть простым — это достойное стремление в любом дизайне, а попытаться сделать нечто простым трудно. Однако при попытке решить (или даже выразить) сложные задачи, порой необходим сложный инструмент. Сложность и запутанность не лучшие черты языка программирования, но существует золотая середина, при которой в языке возможно создание элегантных абстракций, простых в понимании и использовании. Из-за стремления к простоте в Go отсутствуют конструкции, которые в остальных языках воспринимаются как что-то естественное. Вначале это может показаться хорошей идеей, но на практике выходит многословный код. Причина этому должна быть очевидна — необходимо, чтобы разработчикам было просто читать чужой код, но на самом деле эти упрощения только вредят читаемости. Сокращения в Go отсутствует: либо много, либо ничего. К примеру, консольная утилита, которая читает stdin либо файл из аргументов командной строки, будет выглядеть следующим образом: Хотя и этот код пытается быть как можно более общим, принудительная многословность Go мешает, и в результате решение простой задачи выливается в большой объем кода. Вот, к примеру, решение той же задачи на D: И кто теперь более читабельный? Я отдам свой голос D. Его код куда более читаемый, так как он более явно описывает действия. В D используются концепции куда сложнее (прим.пер.: альтернативный вызов функций и шаблоны), чем в примере с Go, но на самом деле нет ничего сложного в том, чтобы разобраться в них. Популярное предложение для улучшения Go — это обобщенность. Это хотя бы поможет избежать ненужного копирования кода для поддержки всех типов данных. К примеру, функцию для суммирования списка целых чисел можно реализовать никак иначе, кроме как ее копипастой ее базовой функции для каждого целого типа, другого способа нет: И этот пример даже не работает для знаковых типов. Такой подход полностью нарушает принцип не повторять себя (DRY), один из наиболее известных и очевидных принципов, игнорирование которого является источником многих ошибок. Зачем Go это делает? Это ужасный аспект языка. Тот же пример на D: Простое, элегантное и прямо в точку. Здесь используется функция reduce для шаблонного типа и предиката. Да, это опять же сложнее варианта с Go, но не столь уж сложно для понимания умными программистами. Который из примеров проще поддерживать и легче читать? Я полагаю, читая это, программисты Go будут с пеной во рту кричать: "Ты делаешь это не так!". Что же, есть еще один способ сделать обобщенную функцию и типы, но это полностью разрушает систему типов! Взгляните на этот пример глупого исправления языка для обхода проблемы: Эта имплементация Reduce была позаимствована из статьи Idiomatic generics in Go (прим.пер.: перевод не нашел, буду рад, если поможете с этим). Что же, если это идиоматично, я бы не хотел увидеть не идиоматичный пример. Использование interface{} — фарс, и в языке он нужен лишь для обхода типизации. Это пустой интерфейс и все типы его реализуют, позволяя полную свободу для всех. Этот стиль программирования до ужаса безобразен, и это еще не все. Для подобных акробатических трюков требуется использовать рефлексию времени выполнения. Даже Робу Пайку не нравятся индивиды, злоупотребляющие этим, о чем он упоминал в одном из своих докладов. Я бы взял шаблоны D вместо этой чепухи. Как кто-то может сказать, что interface{} более читаем или даже типобезопасен? У Go есть встроенная система зависимостей, построенная поверх популярных хостингов VCS. Поставляемые с Go инструменты знают об этим сервисах и могут скачивать, собирать и устанавливать из них код одним махом. Хотя это и здорово, есть крупная оплошность с версионированием! Да действительно, можно получить исходный код из сервисов вроде github или bitbucket с помощью инструментов Go, но нельзя указать версию. И снова простота в ущерб полезности. Я не в состоянии понять логику подобного решения. После вопросов о решении этой проблемы, команда разработки Go создала ветку форума, в которой изложили, как они собираются обойти этот вопрос. Их рекомендация была просто однажды скопировать весь репозиторий себе в проект и оставить "как есть". Какого черта они думают? У нас есть потрясающие системы контроля версий с отличным теггированием и поддержкой версий, которые создатели Go игнорируют и просто копируют исходные тексты. По-моему мнению, Go был разработан людьми, которые использовали Си всю свою жизнь и теми, кто не хотел попытаться использовать что-то новое. Язык можно описать как Си с дополнительными колесиками(ориг.: training wheels). В нем нет новых идей, кроме поддержки параллелизма (который, кстати, прекрасен) и это обидно. У вас есть отличная параллельность в едва ли годном к употреблению, хромающем языке. Еще одна скрипучая проблема в том, что Go — это процедурный язык (подобно тихому ужасу Си). В итоге начинаешь писать код в процедурном стиле, который ощущается архаичным и устаревшим. Я знаю, что объектно-ориентированное программирование — это не серебряная пуля, но было бы здорово иметь возможность абстрагировать детали в типы и обеспечить инкапсуляцию. Go был разработан, чтобы быть простым и он преуспел в этой цели. Он был написан для слабых программистов, используя в качестве заготовки старый язык. Поставляется он в комплекте с простыми инструментами для выполнения простых вещей. Его просто читать и просто использовать. Он крайне многословный, невыразительный и плох для умных программистов. Спасибо mersinvald за правки /dev/usr