LINUX.ORG.RU

Почему Go это плохо, и он вам, на самом деле, не нужен.

 ,


7

15

Давайте я вам поясню про язык Go, откуда у него растут корни, и почему его на самом деле не стоит использовать. То что напишу ниже, это взято как из инсайдерской информации, так и из материалов, доступных в интернетах.

Дело в том, что Go это, на самом деле, «решение» внутренних гугловских проблем. Но отнюдь не проблем горизонтального масштабирования серверного ПО, как многие почему-то думают. Он приспособлен специально для использования в гугле вот в каком контексте.

Гугл нанимает большое количество тупых студентов, только-только после вуза или ПТУ, и заставлять их писать хоть какой-то простой код. И делать минимум ошибок, при этом. Для этого Go сделан таким тупым и упрощенным. И выкинут в паблик он только для того, чтобы вероятность, что у такого студента, только пришедшего в гугл, было хоть какое-то знание Go, была выше нуля.

Но дело вот в чем. В гугле, на самом деле, над каждой командой гошников стоит тимлид, или целая группа, который/которая вот этим взаимозаменяемым роботам-гошникам расписывает всю систему, чуть ли не вплоть до состояния конечного автомата, до if-ов, и показывает куда и что писать. Поэтому же Go на корню режет всю креативность, поэтому там нет практически никаких средств абстракции, и поэтому он не дает делать вообще ничего сложного. Дабы программисты на нем вообще ничего лишнего не думали, а кодировали все чуть ли не побуквенно по указаниям умных людей.

Из гугла же идет маразматическая система управления зависимостями Го, которая заточена на монорепы.

Тут возникает вопрос - а почему этому тимлиду не дать в руки кодогенератор, вместо всей этой accidental complexity, возникающей из-за огромного количества строк кода, и из-за затрат на коммуникацию?

А тут надо понимать, как внутри устроены огромные корпорации типа гугла.

Их давно пожрал рак бюрократии. Там у менеджерских и околоменеджерских должностей один из главных критериев промоушнов, или вообще даже ассесмента(усидения на должности), это количество людей у тебя в подчинении. И количество говнокода в вакууме которая твоя команда написала. И вот все эти люди, сидящие на более-менее средне-высоких должностях, постоянно бодаются за эти промоушны и ассесменты. Это их главная и единственная цель. Поэтому, ни о какой эффективности тут речи не идет вообще от слова совсем. Тут главное - корпоративные игры, количество голов в твоем стаде и количество и размер высеров, которые это твое стадо произвело(причем буквально, важны SLOC).

Естественно, это все отражается на качестве продуктов, и это видно как по полному прекращению инноваций в гугле, так и по постоянно мелькающим и закрывающимся высерам этой компании - hangouts, duo, google plus, google wave, и прочее и прочее, можете еще вспомнить много чего.

Если у вас в компании такой «модели управления» нет, и более того, у вас нет возможности нанимать крайне высококвалифицированных людей за крайне много денег, единственное назначение которых будет расписывать стаду гошников(которые тоже стоят немало денег просто из-за количества) систему до уровня конечного автомата, то вам этот язык и вся его экосистема нахрен не сдалась.

Никакой мифической простоты в отладке и в понимании кода Go не приносит. Да и сложность программных систем растет совершенно не из-за понятности/непонятности какой-то отдельной взятой строчки кода или функции. Потому, что, во-первых, понятность это понятие субъективное, во-вторых потому, что, отдельно взятая фунцкия на 5 строк понятна любому опытному программисту, будь она написана хоть на Rust, хоть на Common Lisp.

Сложность программных систем возникает из-за их размера. И Go эту проблему значительно ухудшает. Человек не может удерживать в голове слишком много вещей, даже если каждая отдельная вещь - очень простая. Количество RAM в голове ограничено.

В случае если вы не хотите выкидывать кучу денег просто так, и скорее предпочли бы нанять немного, но более-менее опытных программистов, Go будет только вреден, потому что все вменяемые люди от него, на самом деле, плюются. Он реально отталкивает опытных людей, которые способны понять сложные требования и написать, и поддерживать, более-менее сложные системы уровнем хотя бы нескольких сервисов плюс БД и MQ.

★★
Ответ на: комментарий от lovesan

Visitor это про двойную диспетчеризацию.

Да нет, это одно из применений. До C++11 чаще всего я видел Visitor там, где надо было присунуть функцию параметром, но при этом никто не хотел париться с сишными указателями.

То, что ты описал, осталось, но это довольно редкий случай. В итоге, теперь Visitor почти не используется. А теперь, когда добавили концепты, и для описанного тобой случая он не особо больше нужен.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

Каким образом лямбды заменяют визитор?

Лямбды это вообще про другое. И во всяких вон жабосишарпах они и так есть, и при это не отменяют необходимость визитора. Без диспетчеризации тебе придется if-ы городить.

Другой пример это проход по какому-то дереву, например дереву выражений.

Есть условно говоря, класс AstNode и его наследники, всякие там AdditionExpressionNode и прочая. И есть классы типа Evaluator, Printer и все такое.

Тоже требуется двойная диспетчеризация. Не пойму как тут в принципе лямбды помогут и каким боком.

lovesan ★★
() автор топика
Ответ на: комментарий от lovesan

В C# вон на самом деле есть хитрый хак, называется dynamic.

типа есть у нас две функции, допустим

void Foo(int x, int y);

и void Foo(string x, string y);

И мы перед тем как вызывать, мы пишем

dynamic obj1 = …; dynamic obj2 = …;

и потом вызываем типа Foo(obj1, obj2);

.NET DLR нам выберет конкретно нужный метод в рантайме сообразно типам аргументов. Т.е. это кастрированные обобщенные функции такие.

lovesan ★★
() автор топика
Ответ на: комментарий от lovesan

Есть условно говоря, класс AstNode и его наследники, всякие там AdditionExpressionNode и прочая. И есть классы типа Evaluator, Printer и все такое.

Тоже требуется двойная диспетчеризация. Не пойму как тут в принципе лямбды помогут и каким боком.

Такие вещи в современных плюсах можно делать на базе std::variant и std::visit без классов и наследования. Но с лямбдами, если используется трюк с overloaded:

 std::visit(overloaded{
            [](auto arg) { std::cout << arg << ' '; },
            [](double arg) { std::cout << std::fixed << arg << ' '; },
            [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
        }, v);

Пока так, пока паттерн-матчинг еще не завезли.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Есть условно говоря, класс AstNode и его наследники, всякие там AdditionExpressionNode и прочая. И есть классы типа Evaluator, Printer и все такое.

Тоже требуется двойная диспетчеризация. Не пойму как тут в принципе лямбды помогут и каким боком.

Такие вещи в современных плюсах можно делать на базеstd::variantиstd::visitбез классов и наследования. Но с лямбдами, если используется трюк с overloaded:

std::visit(overloaded{
           [](auto arg) { std::cout << arg << ' '; },
           [](double arg) { std::cout << std::fixed << arg << ' '; },
           [](const std::string& arg) { std::cout << std::quoted(arg) << ' '; }
       }, v);

Пока так, пока паттерн-матчинг еще не завезли.

Да, я тоже хотел подобную тему притащить. Она, правда, с наследованием не работает. Но для описанного случая наследование не нужно, потому что общий интерфейс можно опять же задать через концепты.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от eao197

Два чая за D. Отличный язык, но пиара мало, поэтому вместо него нишу заняла разная пакость вроде руста и гой.

Hertz ★★★★★
()

Потыкал этот ваш Гоу, оказался вполне приятным язычком (для си-подобного поделия).

Компиляция моментальная и безгеморройная, одна команда — и у тебя есть самодостаточный бинарник не шибко вопиющих размеров (конечно, хелловорлды на чём угодно быстро компилятся, так что не показатель; но отсутствие необходимости дрочить вприсядку вебпакомавены с нюгетоавтотулзами прям подкупает).

Ещё понравилось решительное выкидывание в помойку наследования и всего связанного с ним геморроя, уклон в сторону утиной типизации (похоже на тупоскрипт в этом плане; ещё бы статическая типизация была опциональной, как в тупоскрипте…).

Сборщик мусора, конечно. Concurrency model с (более-менее) человеческим лицом вместо обязательного ручного дрочева мьютексов, а как же.

В общем, есть явные шаги в сторону практичности по сравнению с прародителями, что не может не радовать.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 3)
Ответ на: комментарий от Nervous

одна команда — и у тебя есть самодостаточный бинарник не шибко вопиющих размеров

Дополню: под все возможные ОС кросскомпиляция из коробки.

Zhbert ★★★★★
()
Ответ на: комментарий от hateyoufeel

предложу посмотреть на C, в котором как и в Golang нихрена нет

Ты сравнил эверест c муравьиной кучкой под забором. В C можно все. Это почти ассемблер. В гошке можно только раз-два-три и не более того.

slew
()
Ответ на: комментарий от hateyoufeel

Заметь, не говорил про всякие RAII, метапрограмминг и прочее подобное, говорил про низкоуровневость. И тут в C можно все (чего нельзя в лишпах, плюсах и прочих жабах).

slew
()
Ответ на: комментарий от slew

говорил про низкоуровневость

C не является низкоуровневым языком.

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

По этой метрике копипаста с if err != nil { return nil, err } просто чудовищно просасывает. От неё в глазах рябит, когда у тебя после каждого вызова функции это говно.

придет время и придумают оператор типа

abandon(err, …)

который будет синт. сахаром для

if err != nil { return … }

alysnix ★★★
()
Ответ на: комментарий от slew

И тут в C можно все (чего нельзя в лишпах, плюсах и прочих жабах).

А можно с этого места поподробнее?

ЕМНИП, в Си можно обращаться к неинициализированным компонентам union. Т.е., в Си это вроде как легально:

union {
  int a;
  float b;
} u;
u.a = 12345;
float c = u.b;

тогда как в C++ такое считается UB.

Еще в Си можно скастить указатель к нужному типу и считать, что это валидный указатель на корректно сконструированный объект:

struct X {...};

X * x = calloc(1, sizeof(X));
x->...; // Тут в Си нет проблем.

void * shared_mem_ptr = map_some_shared_memory();
X * x2 = (X *)(((char *)shared_mem_ptr) + sizeof(data_header));
x2->...; // И тут в Си нет проблем.

тогда как в C++ до (если не ошибаюсь) C++20 это формально было UB, т.к. компилятор не видел корректно сконструированного посредством calloc экземпляра типа X, как и не видел корректно сконструированного где-то в разделяемой памяти. В С++20 вроде бы починили ситуацию с calloc-ом, а в C++23 добавили start_lifetime_as для второго случая.

Еще можно вспомнить наличие ключевого слова restrict в Си.

Что еще можно делать в Си, чего нельзя в C++?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

ЕМНИП, в Си можно обращаться к неинициализированным компонентам union. Т.е., в Си это вроде как легально:

потому что Си для системного программирования и должен позволять все. например доступ к битам float представления нужен либам эмуляции плавающей арифметики.

alysnix ★★★
()
Ответ на: комментарий от alysnix

Э… Я не понял в чем смысл вашего комментария. Меня интересует перечень мест, в которых Си вроде как позволяет делать все, тогда как C++ не позволяет.

Т.к. пример с union уже входит в этот список, то ваш комментарий не добавляет ничего нового и интересного.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

ЕМНИП, в Си можно обращаться к неинициализированным компонентам union. Т.е., в Си это вроде как легально

Не совсем.

6.5.2.3 Structure and union members

  1. If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

Т.е. может рвануть, а может и нет. Сишный стандарт вообще жопой писан. Но в самом доступе UB нет, если нет проблем с выравниванием и подобным. Зависит от типов внутри union.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от alysnix

потому что Си для системного программирования и должен позволять все. например доступ к битам float представления нужен либам эмуляции плавающей арифметики.

Назови мне язык, в котором нет доступа к битам float. Ну кроме Brainfuck.

hateyoufeel ★★★★★
()
Ответ на: комментарий от alysnix

потому что Си для системного программирования и должен позволять все. например доступ к битам float представления нужен либам эмуляции плавающей арифметики.

Кхе-кхе, давай-ка проверим это утверждение:

$ git -C src/linux grep -El $'\t(float|double)' virt

И ничего.

cumvillain
()
Ответ на: комментарий от cumvillain

а к какому программировнию относится написание библиотек эмуляции плав. арифметики?

предложите термин.

alysnix ★★★
()
Ответ на: комментарий от cumvillain

у вас какая-то извращенная логика. по-вашему, все что можно сделать на питоне уже не может относится к системному программированию в принципе? то есть любой код написанный на питоне, исключает его «системность» и аналогичный код не может встречаться в системном программировании?

а вы странный

кстати, а какой код уж точно «системный»?

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от cumvillain

копирование памяти побайтно - это прикладное программирование? на питоне это можно сделать?

входит в системную либу практически любого языка небось.

и эмуляция плав точки тоже.

alysnix ★★★
()
Ответ на: комментарий от cumvillain

системная либа языка реализует функции оперсистемы? ничоси. то есть вместо линукса просто можно взять сислибу языка и жить хорошо?

alysnix ★★★
()
Ответ на: комментарий от alysnix

системная либа языка реализует функции оперсистемы? ничоси. то есть вместо линукса просто можно взять сислибу языка и жить хорошо?

Если я завтра заменю тебе лялекс на какой-нибудь Redox, твое приложение этого даже не заметит.

cumvillain
()
Последнее исправление: cumvillain (всего исправлений: 2)
Ответ на: комментарий от alysnix

В любом случае, какое все это имеет отношение к C? Как мы уже выяснили, ты можешь взять Golang и написать все то же самое.

cumvillain
()
Ответ на: комментарий от cumvillain

В любом случае, какое все это имеет отношение к C?

вы хотите сказать, что сишный union не имеет к си отношения? или вы не врубаетесь, что union это не просто способ положить в одно место значения разных типов, а способ обойти типизацию, и получить например битовое представление значений неких типов, вот например как с float.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)
Ответ на: комментарий от alysnix

вы хотите сказать, что сишный union не имеет к си отношения? или вы не врубаетесь, что union это не просто способ положить в одно место значения разных типов, а способ обойти типизацию, и получить например битовое представление значений неких типов, вот например как с float.

Это можно сделать на любом языке. Ты можешь сделать такой же упакованный тип и отдать его наверх через cишный FFI. И никто не заметит разницы, лол.

cumvillain
()
Ответ на: комментарий от cumvillain

Это можно сделать на любом языке. Ты можешь сделать такой же упакованный тип и отдать его наверх через cишный FFI. И никто не заметит разницы, лол.

вы с чем спорите хоть? причем тут «любой» язык? мы говорим про си, и зачем там union.

alysnix ★★★
()
Ответ на: комментарий от alysnix

вы с чем спорите хоть? причем тут «любой» язык? мы говорим про си, и зачем там union.

Ты начал рассказывать что C низкоуровневый язык (нет), который почти ассемблер (нет), и на котором можно делать все что угодно (нет).

cumvillain
()
Ответ на: комментарий от cumvillain

Ты начал рассказывать что C низкоуровневый язык (нет), который почти ассемблер (нет), и на котором можно делать все что угодно (нет).

нет. ни одного из этих утверждений я не делал. проверьте посты. я высказался только про юнион, и почему он принципиально нужен для языка системного программирования. и все.

ps. все эти ваши «утверждения» не имеют строгой формулировки - «почти ассемблер, все что угодно, низкоуровневый». это чисто гуманитарные утверждения. с ними можно спорить до хрипоты.

alysnix ★★★
()
Последнее исправление: alysnix (всего исправлений: 1)

Дактайпинг в статическом языке. Этого факта достаточно для того, чтобы понять насколько надо быть отчаяным, чтобы использовать это где-то, где больше 100 строк.

putch
()
Ответ на: комментарий от whereisthelinus

Уровень познаний об этих компаниях подстать гошнику.

VK лол - да там повсюду внутри этот их собственный пых сделанный на манер фейсбучного недопыха. Дальше даже комментировать лень.

lovesan ★★
() автор топика
Ответ на: комментарий от lovesan

Я в одних работал, в другие собеседовался, мне их тимлиды говорили. А ваше мнение на чём основано? Что скажете про количество открытых вакансий (надеюсь, сможете посчитать)?

https://team.vk.company/vacancy/?specialty=282&town=&tag=2225&search=

https://team.vk.company/vacancy/?specialty=282&town=&tag=2231&search=

whereisthelinus
()
Последнее исправление: whereisthelinus (всего исправлений: 1)
Ответ на: комментарий от Nervous

Потыкал этот ваш Гоу

Спецификация написана человеческим языком, с разъяснениями и примерами; после небольшой практики читается как роман.

Продолжаю наблюдение.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от putch

Я не понимаю зачем нужна возможность реализации интерфейса без явного указания того, что я хочу, чтобы моя реализация являлась реализацией именного этого интерфейса. То, что там есть метод с таким же названием еще ничего не значит. В купе с отсутствием алгебраических типов данных мы получаем полностью неявное поведение без какой либо проверки на исчерпываемость. Зачем мне такой глупый компилятор? Я искренне не могу понять что получает компания, которая пишет на го. Должна же быть хоть какая-то компенсация всему этому безобразию.

putch
()
Ответ на: комментарий от putch

зачем нужна возможность реализации интерфейса без явного указания

Дык чтобы использовать значения своего типа там, где ожидается экземпляр интерфейса. Можно в комментариях указать, какой именно это интерфейс, если имеется куча одинаковых интерфейсов с разной семантикой методов (фу, фу).

Если имеется куча одинаковых интерфейсов с одинаковой семантикой методов — это на самом деле один интерфейс %)

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)
Ответ на: комментарий от Nervous

Все же наоборот. Это очень полезно когда можно чужие объекты (без возможности указать им реализуемый интерфейс) использовать в своем коде, будто они его реализуют.

urxvt ★★★★★
()
Ответ на: комментарий от Nervous

Продолжаю наблюдение.

ШОК! ТРЕПЕТ! gofmt использует смесь табов и пробелов для форматирования!

Впрочем, пока форматированием занимается gofmt, a не я, это безразлично. Осадочек, конечно, остаётся, но… безразлично.

Нет, правда. Я спокоен. Спокоен, говорю.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 1)

Поржал с треда. Лавсан, условно, такой:

если лодка имеет скорость 20 км/ч относительно течения, а течение – 10км/ч, то скорость лодки относительно берега будет (30+10)/(1+30*10/c^2)"

А гоферы ему:

Да я сам капитан дальнего плавания и могу тебя заверить, что всё не так!

Даже не в курсе вообще про что речь, на разных языках говорят.

Кстати, интересная деталь – и секта скопцов на Руси, и часть АйТи использует(овала) карабельную тематику («взойти на корабль» и «радение корабликом» – у первых, «гребцы» и «галлёры» – у вторых). При этом и туда, и сюда вовлекают путём обещания материального вознаграждения. Совпадение?

Calm
()
Ответ на: комментарий от putch

Я не понимаю зачем нужна возможность реализации интерфейса без явного указания того, что я хочу, чтобы моя реализация являлась реализацией именного этого интерфейса.

Это нужно для decoupling’а. Вот есть у вас в коде интерфейс, а у Amazon или Uber есть либа, которая ему удовлетворяет. Вы просто берёте её и используете. В других языках надо адаптер писать, тут всё просто работает. Разумеется интерфейсы надо такие объявлять, что нужная либа сразу подходила. Захотите сменить - напишите адаптер для новой либы, но старого интерфейса (буквально 0 строк изменятся в существующем коде).

То, что там есть метод с таким же названием еще ничего не значит.

Название действительно ничего не значит. Чтобы удовлетворять интерфейсу нужно чтобы сигнатура 1:1 совпадала, и название, и аргументы, и возвращаемое значение. Если подходит, то гарантированно заработает.

whereisthelinus
()
Ограничение на отправку комментариев: