Как стать автором
Обновить

Комментарии 479

Ну вот, очередной не разобравшийся в языке пишет статью со своим мнением. «Странности» компиляции связаны с тем что компилятор ставит точку с запятой в конце каждой строки автоматически, кроме открывающих скобок и запятых
Какое мне, простому разработчику, дело до сложностей компилятора при работе с промежуточным представлением кода?
Это не баг, а полезная фича.
Элементы списка унифицированы, их можно комментировать, копипастить и т.д. без необходимости следить, есть ли запятая на последнем элементе или нет.
Это уменьшает кол-во ошибок при разработке софта.
Так что это очко в пользу Go.

В любом случае, это отловится на этапе компиляции, что вроде как соответствует духу Go?
Зачем тогда нагружать компилятор неожиданными для программиста функциями по дополнению кода?

ну тут проблема в стиле — «вот в json не нужно запятую после последнего элемента ставить, а в Go нужно, ууууу, неудобно».
@zubor правильно подметил — запятая после последнего элемента в много строчном объекте требуется специально (даже Russ Cox об этом писал), как раз из-за того, что при удалении и добавлении элементов (и генерации кода) не нужно было постоянно проверять последний ли элемент это или нет.
Т.е. можно [случайно] удалить последний элемент в списке и никто этого не заметит.
Или скопипастить лишнее в середину — тоже всё ОК будет: всё с запятыми.
На код-ревью заметят, там «красненьким» подсветится.

Это только в случае удаления последней строки, в середину тоже самое, то есть редкий кейс. Да и правильно — git diff и код ревью вам в помощь.

Редкий не редкий, но зачем убирать такую защиту?
А если полагаться на дисциплинированность программистов и повсеместную отличную организацию их работы, то можно наверное много чего придумать, для упрощения работы компилятору.
Это не защита, это источник ошибок. При добавлении элемента, нужно постоянно изменять предыдущею строку, что еще и неудобно.
Ошибка пойманная компилятором — не ошибка.
А вот, повторю, удаление последнего элемента списка в Go должно отлавливаться уже на других этапах. Которых может и не быть.
А работа с синтаксисом языка у опытного программиста вообще на автомате происходит: думаешь о том что должно быть («функция такая-то», «добавить значение в конец списка» или вообще думаешь как алгоритм выразить в языке), а банальный синтаксис руки сами оформляют. Вот если какие-то хитровывернутые конструкции — там да, надо думать и над синтаксисом.
А уж запятую поставить или убрать — вообще не проблема.
Как часто вы случайно удаляли последний элемент в списке?
У меня никогда такого не случалось.
Ошибка — это то, что вам нужно исправить. Вот с удалением (или добавлением) запятой после редактирования кода я сталкивался — json был невалидный.
Статистику такую конечно не веду, но вполне себе могу представить рабочую ситуацию (т.е. не умозрительно, а из каких-то глубин памяти), что при выделении и копи-пасте захватил лишнего (последнюю строку).
И компилятор ругнётся сразу в двух местах: и там откуда забрал лишнее (список остался с висящей в конце запятой) и там куда вставил (лишний, не последний элемент в списке без запятой).
А в Go, выходит ни то, ни другое компилятор не заметит.
Вы на компилятор возлагаете какую-то совсем уж странную функцию: «контроль корректности заполнения данных программистом». К тому же не понятно, каким образом отсутствие запятой в конце списка вам должно помочь.
Отвечу на последний вопрос:
Если в конце списка и только в конце списка предполагается запятая, то там откуда я забрал лишнюю (последнюю) строку — в конце списка окажется несанкционированная запятая.
А там куда я вставлю вырезанное — будет 2 строки без запятой.
Да это-то я понял. Я не понял, чем именно последняя строка списка так сильно отличается от, допустим, предпоследней, или первой, или второй сверху?

В чём проблема удаления именно последней строки? Почему именно её вы пытаетесь решить с таким рвением, старательно игнорируя тот забавный факт, что присутствие/отсутствие запятой в последней строке никак не влияет на не-последние.

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

Чота вы с ветряными мельницами воюете…
Да это-то я понял. Я не понял, чем именно последняя строка списка так сильно отличается от, допустим, предпоследней, или первой, или второй сверху?

Черт. Я понял! Нужно для каждой строки свой символ ввести. Тогда уж точно будет очень удобно и компилятор защитит нас от ошибки
Можно еще так — четные строки с запятой, нечетные без.
Получается 100% защита от случайного удаления любой строки.
Как тебе такое, 5oclock?
Можно вспомнить, что кроме кодов обнаружения ошибок еще есть избыточное кодирование, которое позволит её исправить! Нужно ставить 3 запятых где она должна быть, и 0 там, где не надо.
Блин, сперва прям порадовался гениальности решения, но…

Это же не защитит от случайного удаления ровно двух соседних строк! Что делать???
Увеличиваете количество запятых, и всё. Для исправления N ошибок требуется N+2 кодирование. Выбираете такое N, которое больше нравится, и используете соответствующее количество запятых.

Короче, надо просто добавить капчу в IDE, когда кто-то пытается удалить последнюю строку.

«Решите простенькое интегральное уравнение, чтобы подтвердить, что вы действительно хотите удалить эту строку».
Я придумал, придумал! Еще лучше придумал!

1. Нужно строки нумеровать (строго по порядку) — тогда мы защитимся не только от удаления строки, но еще и от случайных перемещений строки.
2. Вместо спецсимвола нужно использовать хеш от номера строки + её содержимого! Тогда мы заодно сможем защититься от случайного изменения строки!

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

В теории, мы можем защититься еще и от удаления/правки строки сторонним злоумышленником (если этот самый хеш подписывать личной ЭЦП разработчика).

И от чтения врагами (шифрованием получившегося).

ТакЪ победимЪ!!!
Я-то не воюю.
Это создатели Go решили из каких-то своих соображений сделать «не так как у всех» и заодно сломали такую вот «защиту последней строки», убрали наглядное подтверждение завершённости списка для читающего код.

Это как питон со своими отступами.
Удалил отступ у последней строки цикла или if'а и никто этого не заметит: ни компилятор, ни тот кто будет читать/сопровождать программу…
убрали наглядное подтверждение завершённости списка для читающего код.


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

https://github.com/golang/go/issues/23966#issuecomment-377997161


For example, the hacked-up blog post system I built stores a JSON blob at the top of each file, above the post text, because it was very easy to implement that. But I am sick of needing to leave out the comma after the last key-value pair, because it makes adding a new key-value mean editing the previous one too. This is exactly why we allow trailing commas in Go literals. Those annoyances add up.
Это не защита, это ересь какая-то, да еще и грабля впридачу.
А чего Вы ожидали? Человек разбирался в языке за один присест с книгой Введение в программирование на Go ))
Я работаю с Питоном несколько лет, попробовав Go остался доволен. Все те «недостатки» про которые все говорят принял как данность, типа: «А, хорошо — здесь это так работает и устроено так! Запомним!»
Почему-то некоторые начинают сравнивать этот язык со своим любимым/используемым…
Жаль на работе не дают использовать, мол, специалистов мало на рынке (
А чего Вы ожидали? Человек разбирался в языке за один присест с книгой Введение в программирование на Go ))

С чего вы взяли? Я вообще в основном со спецификацией языка работаю и работаю давно.
Ну шутка же была, что уж Вы — смайлики в конце намекают на рофл. Извините.
Я вообще в основном со спецификацией языка работаю и работаю давно.

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


make([]int, 50, 100)
new([100]int)[0:50]


Вот это, все таки, немного разные вещи. Не то чтобы на выходе вы получали принципиально разный результат… Но констракт слайса длины 50 с капом 100 и создание массива из 100 элементов и после этого взятие слайса из первых 50… Как минимум, в полученом слайсе будет кап 50, и поведение при «растягивании» оного может сильно различаться.
Это пример из документации, там утверждается, что это идентичные конструкции.
Перечитал, в этом моменте согласен, был неправ, посыпаю голову пеплом.

Однако некоторые ваши позиции достаточно спорны.
var i int = 3
j := 6


Вторая строка — просто сокращенная запись с автовыводом типа. При этом достаточно очевидно, что именно при объявлении переменной предпочтителен первый вариант, ввиду явного указания типа и по принципу наименьшего удивления.
Однако для возврата значения из функции мы имеем уже:
var i int = someFuncReturningInt()

против
i := someFuncReturningInt()


На этом месте нужность сокращенной записи все еще не очевидна, однако при возврате из функции нескольких значений становится понятно, для чего придумана сокращенная запись:
result, err := some2ResFunc()
// вполне себе разворачивается в:
var result ResultType
var err error
result, err = some2ResFunc()


Так что претензия к элементарному автовыводу типов выглядит достаточно странной.
Вообще нет претензии к элементарному автовыводу типов, я просто им наслаждаюсь. Я просто говорю, что в этом месте немного песне единообразия наступили на горло. Или недодумали.
Ну, собственно:

var i int — способ решения «классической проблемы» char *(*(**foo[][8])())[]

Вариант, собственно, хорош, но при этом он ведет(ввиду возможности множественных возвратов) к:
var res int
var err error
res, err = someFunc()


А это уже достаточно многословно. И эта проблема решается
res, err := someFunc()


Сложно придумать что-то лучшее…
А для j := 6 оно, собственно, не предназначалось, и не рекомендуется.

Вы ж сами написали: "Простой язык — обратная сторона бедности синтаксиса — возможность освоить язык за 1 день. Даже не за 1 день, а за 1 присест."
Что, мягко говоря, вообще не правда. Go — весьма сложный для освоения язык, потому что граблей по нему разбросано неимоверное количество. Даже статьи с подборками писали, типа 50 Shades of Go. Часть граблей имеет какое-то более-менее разумное объяснение, а часть — WAT чистой воды. Но в любом случае, освоить его быстро не получится, т.к. опереться на предыдущий опыт с другими языками не получится.

Справедливости ради, Go осваивается не медленнее любого другого enterprise-языка, а в подавляющем количестве случаев быстрее.

Слишком сильно зависит от бэкграунда, поэтому я бы сказал, что сравнить в общем случае невозможно. Кому-то быстрее Go получится освоить, кому-то — C#.
Я больше про то, что все эти "за 1 день" — не более, чем маркетинговый булшит.
Что-то начать писать можно на 1-й день на любом языке (особенно если у вас уже есть пяток ЯП в арсенале), но это не значит, что он освоен.

Я про то, что:
а) в Go сильно меньше языковых конструкций в принципе, чем в той же Java или C++ или C#. В нем реально примерно столько синтаксиса, что, с хорошим бэкграундом в других языках, читать и понимать код сможешь часа за 3 (без бэкграунда — за день-два), не натыкаясь на непонятные языковые конструкции. Он не то что прост, он прямо примитивен с точки зрения синтаксиса и системы типов.
б) В «обросших энтерпрайзом» языках есть достаточно крупные фреймворки, большая стандартная библиотека и вот это вот все, без которых нельзя писать на этих языках эффективно. Навскидку, для Java нужны стримы, коллекции (и понимание того, в каких ситуациях какие лучше использовать), да тонна еще всего. В общем, в той же Java между «пониманием синтаксиса» и «умением писать эффективный код», да простят меня Java-программисты, реально пропасть. В Go пропасть существенно поменьше.
Вы правы, но только в случае с написанием каких-то своих скриптов.
Пытаясь прочитать достаточно сложные библиотеки, вы будете очень сильно разочарованы в том что получается из-за недостатка абстракций и конструкций.

По типу
var descriptor = getDescriptor<Descriptor1/>(param1, param2)

в любом современном строго типизированном языке
или

var descriptor Descriptor1
ok := getDescriptor(param1, param2, &descriptor)


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

Те же интерфейсы, которые казалось бы унифицированы и крайне просты…
Смотря в исходники(написанный людьми из гугла) я вижу:
    // Implements Something interface
    func (o object) doSomething (i Interface{}) {}

    // Implements AnotherThing interface
    func (o object) doAnotherThing (i Interface{}) {}


Да, самоучитель по GO я действительно(уже довольно давно) прошел часа за 3. Но читать его мне до сих пор местами крайне сложно, если имеется какая-то более-менее сложная логика требующая определенного кол-ва абстракций.
Мне кажется, проблема в том, что вы сетуете на то, что Go не Java…

var descriptor = getDescriptor<Descriptor1/>(param1, param2)


Выглядит очень похоже на абстрактную фабрику. Что есть неидиоматично для Go.

var descriptor Descriptor1
ok := getDescriptor(param1, param2, &descriptor)


Как минимум, именование функции странное для этого кейса. Что должна, собственно, делать эта функция?

И почему, собственно, не сделать *Descriptor1 ресивером функции?

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


Вот и я говорю: не пытайтесь на Go писать на Java.

Те же интерфейсы, которые казалось бы унифицированы и крайне просты…


Видимо, вы переусложняете. Семантика интерфейсов в Go отличается от общепринятой для ООП-языков.

// Implements Something interface
func (o object) doSomething (i Interface{}) {}

// Implements AnotherThing interface
func (o object) doAnotherThing (i Interface{}) {}


Абсолютно верно и идиоматично. В Go интерфейс — сущность необходимая принимающему объекту, а не типу, его реализующему. В этом и «одна из главных фич».
Java здесь вообще не при чем, это просто generic.
Сделать ресивером не выйдет т.к. эта функция должна, по сути, возвращать объекты различного типа.
Плюс ко всему, это код из библиотеки kubernetes, а не какой-то притянутый за уши пример, где java разработчики пытаются писать на GO.

В интерфейсах я делал акцент на комментариях, которые явно говорят о том, что семантики интерфейсов в GO явно не хватает.
Сделать ресивером не выйдет т.к. эта функция должна, по сути, возвращать объекты различного типа.


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

Плюс ко всему, это код из библиотеки kubernetes, а не какой-то притянутый за уши пример, где java разработчики пытаются писать на GO.


Вот этот?

// Implements Something interface
func (o object) doSomething (i Interface{}) {}

// Implements AnotherThing interface
func (o object) doAnotherThing (i Interface{}) {}


Абсолютно нормальный код, так оно и должно быть. Что с ним не так?

В интерфейсах я делал акцент на комментариях, которые явно говорят о том, что семантики интерфейсов в GO явно не хватает.


Вы просто ожидаете от интерфейсов в Go соответствия интерфейсам Java или C#. Ну, собственно, зря. Интерфейсы Go — несколько иная сущность. Точнее, формально — то же самое. Предназначение — сильно разное.

Вы утверждаете, что вам не хватает «абстракций», упрощающих вам жизнь. Собственно, палка (как и любая другая палка) — о двух концах. Абстракции могут жизнь как упрощать, так и усложнять.

Всегда есть trade-off. В некоторых языках (не будем показывать пальцем на Java, C#, C++) абстракции, упрощающие жизнь являются частью языка ценой возможности пиления абстракций, эту жизнь сильно усложняющих. Да и собственно ООП-языки задумывались, исходя из подхода «сначала абстракция». Т.е. предполагают сначала рождение абстракции, а затем уже конкретную реализацию в рамках задуманной абстракции.

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

Собственно, что есть хорошо, и что плохо — вещь сугубо ситуативная. Несложно понять, что каждый из подходов имеет право на существование в определенных условиях. Просто разный подход к проектированию.
1. Этот «неидиоматичный» подход решается введением generic'ов. Generic'и вводят во 2й версии Go.
2. Абсолютно нормальный код, который предполагает написание методов исключительно для реализации интерфейса(исходя из комментариев), что в корне противоречит вашему утверждению про интерфейс исходя из существующей реализации.
2. Ну когда вам нужно реализовать интерфейс, что бы использовать его в библиотеке, то все ок, да. Часто люди упрощают и передают один и тот же обьект, который реализует несколько интерфейсов.
Боюсь, дженерики, в том виде, в котором они появятся в языке-который-вы-не-используете, вызовут у вас не меньшее негодование, чем все остальное.

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


Вы невнимательно читали мое утверждение. Еще раз: в классическом ООП интерфейс — неотъемлемая часть типа (класса). Go не ООП-язык. В Go интерфейс — неотъемлемая часть потребителя. Чуете разницу, или нужны примеры кода?
Да и собственно ООП-языки задумывались, исходя из подхода «сначала абстракция». Т.е. предполагают сначала рождение абстракции, а затем уже конкретную реализацию в рамках задуманной абстракции.

Нет, не задумывались, и таковыми не являются.
Видимо, статья — ответ на очередной виток холивара ООП vs ФП от, без сомнения, очень авторитетного чувака, — должна что-то обосновать в контексте обсуждения процедурного Go vs ООП-языки… Но я не уловил, что конкретно.

Смотри, на пальцах, разница в подходах:
1. Предварительно согласимся в терминологии. Есть «сигнатура» — предопределенное описание сущности. Есть «интерфейс» — сигнатура набора методов, обязательных к реализации. Есть «тип» — некая сигнатура сущности, которая может реализовывать интерфейс, а может не реализовывать. Есть «экземпляр типа» — инициализированный объект, соответствующий сигнатуре типа. Есть «потребитель» — некоторая сущность, принимающая на вход тип, ограниченный определенными критериями (в нашем случае интерфейсом).
2. В классическом ООП реализуемый интерфейс является неотъемлемой и обязательной частью сигнатуры типа. Т.е. вам необходимо явно указать, что тип реализовывает указанный интерфейс.
3. Также интерфейс является неотъемлемой частью сигнатуры потребителя.
4. В Go реализуемый интерфейс не является частью сигнатуры типа, и, по большому счёту, не имеет к оной никакого отношения.

Что это дает.

В классическом ООП для того, чтобы изменить сигнатуру ресивера (в случае, если вам понадобилось уметь работать с несколькими типами), вам нужно заодно поменять сигнатуру потребляемого типа (что ведет к дополнительной грабле вида «тип пришел к нам из сторонней библиотеки, изменить/унаследовать можно не всегда»). В Go для изменения сигнатуры потребителя нам нужно только изменить сигнатуру потребителя, потребляемый тип остается неизменным.

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

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

В «классических» ООП-языках есть инструменты для подхода «сначала абстракция». Есть, заодно, до кучи, целые библиотеки, состоящие исключительно из абстрактных типов/методов, из шаблонов и дженериков. Я не говорю, что это плохо. Я говорю, что в Go от этого решили отказаться — только и всего.
Это называется тайпклассы, которые при этом по некоторому недоразумению применяются автоматически ко всем типам, которые похожи по сигнатуре.

Проектирование тайпклассов несколько отличается от проектирования интерфейсов, но все еще не настолько, чтобы это было кардинально иной деательностью.

В «классических» ООП-языках есть инструменты для подхода «сначала абстракция». Есть, заодно, до кучи, целые библиотеки, состоящие исключительно из абстрактных типов/методов, из шаблонов и дженериков. Я не говорю, что это плохо. Я говорю, что в Go от этого решили отказаться — только и всего.

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


Ну да, идея прикочевала из C++, куда была занесена ветром из Хаскеля.

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


Не по недоразумению, а по замыслу авторов.

Хз, обычно делают так, как чувак из статьи. Нужен класс — пишем класс. Никаких интерфейсов/фабрик/менеджеров.


Вы же понимаете, что:
а) ваша выборка непрезентативна;
б) моя выборка тоже непрезентативна;
в) «обычно делают так» пишут в случает отсутствия пруфов.
НЛО прилетело и опубликовало эту надпись здесь
Ну, гм, в C++ нет тайпклассов.


Ну, видимо, есть, раз один из авторов Go утверждает, что идея заимствована из хаскеля, за основу взята C++-реализация.

Не могу сказать, чтобы это когда-то мешало или было неудобным за всю мою практику.


Собственно, единственное различие: при изменении сигнатуры потребителя необходимо изменять сигнатуру потребляемого типа. В случае структурной типизации такой необходимости нету — только и всего.
Ну, видимо, есть, раз один из авторов Go утверждает, что идея заимствована из хаскеля, за основу взята C++-реализация.

Ну раз один из авторов Go утверждает, то конечно.

НЛО прилетело и опубликовало эту надпись здесь
Я смотрю, вы уже с собой спорить начали. Понимаю, приятно пообщаться с единомышленником.

У неё есть свои преимущества, но есть и свои недостатки.


Абсолютно логично. И это применимо ко всем видам типизации, например.
НЛО прилетело и опубликовало эту надпись здесь
Смотрите, у нас есть, предположим, тип TypeA, который имеет, что естественно, некоторую сигнатуру.

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

В процессе вы рожаете некий TypeB, реализующий функционал, аналогичный TypeA. Тут, я думаю, вы согласны, появление таковой необходимости очень часто бывает обоснованным. И вам нужно, чтобы Method1 на вход мог принимать обе реализации. Что же делать, что же делать?

Правильно, вы пилите интерфейс (пусть будет InterfaceAB), обобщающий оба типа, и меняете сигнатуру Method1, который теперь вместо TypeA на вход принимает InterfaceAB.

И вот в этом моменте вы обязаны явно указать TypeA, что он реализует InterfaceAB, и то же самое сделать для TypeB. Т.е. список реализованных типом интерфейсов — неотъемлемая часть этого самого типа.

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

Собственно, отсюда и рекомендации по использованию интерфейсов в Go: Go-шный интерфейс предельно короток, Go-шный интерфейс определяется рядом с потребителем типа, Go-шный интерфейс описывает ровно то, что нужно потребителю от потребляемого типа, Go-шных интерфейсов много.
НЛО прилетело и опубликовало эту надпись здесь
Часто читаю отзывы, что питонистам нравится Go и все не могу понять — почему?
Чем он вас цепляет после Питона?
Я хоть владею Питоном не профессионально, но даже учить Go и его особенности неприятно. Мне куда ближе тот же Kotlin.
Дешёвый способ получить хороший перфоманс по сравнению с Python, когда это начинает быть важно.
С удовольствием перешёл с питона на го. Как уже сказано в соседнем комментарии — быстродействие приложений заметно выше получается. Потребление памяти заметно ниже.
Интерпретаторы, честно говоря, никогда особо не нравились. Тащить за скриптом чемодан без ручки в виде интерпретатора и библиотек, такое себе развлечение. С го гораздо проще. Ну и по мелочи, потом всё-таки сложилось мнение, что питоновские отступы это не лучшее решение, скобки удобнее. Статическая типизация удобнее. Реализация асинхронности очень понравилась.
В общем, к питону уже не вернусь.
Как раз таки, если оперировать словом «хайп», то оно к питону больше подходит.
Питон тут, питон здесь, питон суют куда только можно. Там где в общем и не очень понятно почему именно питон. Люди, которые даже пары строк написать не умеют и никогда не программировали, есть таких много в айти индустрии, всё равно знают, что питон это круто и модно.
Про Go только второй год не затыкаются. До этого были Scala и Ruby. Ну и где они теперь?
Именно это — хайп. Домашние проектики и десяток стартапов. Go повторит историю Ruby.
Питону уже нормально так лет, он в топ3, он в матером продакшене.
он в матером продакшене

Это да, гигатонны костылей, одноразовых и райтонли скриптов, всякой внутренней автоматизации…
> Домашние проектики и десяток стартапов.

Ничего себе заявления. А вы случайно свои сайтики не в DigitalOcean хостите? А дропбоксом пользуетесь?
Все проекты в CNCF написаны на Go (а те что не были, как linkerd, переписали на Go). Вот тут у Go как раз своя ниша — все что связано с платформой.

Как бы вам не хотелось, но Go это как раз не домашние проектики.

Я пишу на питоне с версии 1.4(примерно с 2003 года), пару лет назад перешёл на go. Так вот основное преимущество go для меня в том, что на нем нельзя так просто выстрелить себе в ногу, как это можно сделать на питоне. Ошибки на этапе компиляции, статическая типизация, потребление памяти, горутины и предсказуемое поведение программы.

Я пишу в компаниях, где принято покрывать код тестами, и при таком подходе на выходе, что Python, что Go дают результаты одинакового качества.
Например, не совсем правда…
НЛО прилетело и опубликовало эту надпись здесь
Чтобы проверить не поменялась ли логика при рефакторинге.
НЛО прилетело и опубликовало эту надпись здесь
Любое бизнес поведение программы.
НЛО прилетело и опубликовало эту надпись здесь
У вас метод с большим количеством вложений if и for в друг друга. При очередном фиксе было решено разбить на 4 разных метода вызывающих друг друга. Но не все вызовы были расставлены правильно.
НЛО прилетело и опубликовало эту надпись здесь
Я дружелюбно вам завидую, но вакансий в моём городе по Haskell нет.
Тут фишка в чем:
— либо вы пишете тесты для проверки логики + тесты на валидность типов входных данных;
— либо вы пишете тесты для проверки логики, а валидность типизации входных данных за вас делает тайп-чекер.

Т.е. тайпчекер — это «встроенный в язык тест на валидность типа входных данных».
НЛО прилетело и опубликовало эту надпись здесь
Довольно сложно представить как это может работать, но я готов поверить, что в Хаскеле это решается дизайном языка.
НЛО прилетело и опубликовало эту надпись здесь
Учитывая наличие в вашем коде subZero, это должен быть fatality checker.
НЛО прилетело и опубликовало эту надпись здесь
Не могу сказать, что много кодил на Python (3), но переход на GO прошел на ура по сл.причинам.
1. компилируемый = скрость
2. Горутины и каналы — изящно, красиво и многопоточно.
3. строгий контроль типов (знаю в питон тоже завезли, но в go оно из коробки был)
4. работа с переменными (динамическое объявление, автоматическая сборка мусора) очень близка к Python, а не к C (чего очень не хочется: ног я себе уже наотстреливал предостаточно)

т.е. есть плюсы и есть знакомые. приятные вещи. Посему переход — приятен.
Golang подходит почти всем, кому, нужен перфоманс в скорости по сравнению со скриптовыми языками, такими как ruby, python, php и даже javascript..., но он не нужен тем кто работает с java, с#…
Простая причина, это почти либа при которой можно девелопить вещи имея стандартные средства для микросервисов, быстро изучается, тяжело отстрелить себе ногу…
а синтаксис и питоновцы, хотя самому нравится питон… могу предположить что go еще более строгий и минимум скрывает своих задвигов за сахаром, как это делают другие интерпретируемые языки
о он не нужен тем кто работает с java, с#…

в данном случае Go упрощает деплоймент и поддержку приложений.
Каким образом?
Деплой? Очень простым: положил бинарь, и оно работает.
Докер-компоуз — не лучший инструмент для прода.

Ну и, в конце концов, вы не разрешили проблему. Вместо .NET-рантайма вы на сервер просто тащите докер. Один фиг на 1 зависимость больше, чем у Go.
Докер-компоуз — не лучший инструмент для прода.

Как раз наоборот. Надо же и оркестровать сервисы, и вот этим всем заниматься.

Ну и, в конце концов, вы не разрешили проблему. Вместо .NET-рантайма вы на сервер просто тащите докер. Один фиг на 1 зависимость больше, чем у Go.

Допустим. Чем это плохо-то?
Как раз наоборот. Надо же и оркестровать сервисы, и вот этим всем заниматься.


Еще раз, docker-compose — не лучший инструмент для прода. Он очень плохо ведет себя под нагрузкой, он не умеет live-reload, он не умеет адекватного управления ресурсами и т.д. и т.п. Более того, docker-compose — всего лишь управлялка над голым докером, который очень не рекомендуется выставлять наружу.
В конце концов, вам дали божественный k8s, а вы на прод голый докер суете. Стыдно должно быть. Я понимаю, что вы, в конце концов, разработчик, а не админ/девопс. А продом должен таки рулить тот, кто умеет его готовить.

Допустим. Чем это плохо-то?


Плохого-то ничего. Это просто опровержение вашего высказывания, что .NET-приложение деплоится не сложнее Go-шного. Ну вот говорю: сложнее. Для вашего случая всегда +1 шаг деплоя относительно Go.

Заметьте, я не говорю, что это прям усраться проблема. Я просто говорю, что N+1 шаг всегда больше, чем N.
Ну ок, трудно с этим спорить. Но на практике разницы я не вижу, что там, что там жмешь кнопку в тимсити и оно полетело в релиз.
тем что не надо обновлять/патчить тот же JVM на всех серверах, где это ранится. А если докер — то тут надо следить за тем, что используют программисты и обновлять какой-нибудь базовый image.

Деплоймент будет гораздо быстрее — компилятор быстрее, плюс не нужно тянуть кучи зависимостей типа docker image с OS, сам docker image будет максимально маленький.
И все в этом духе.
тем что не надо обновлять/патчить тот же JVM на всех серверах, где это ранится. А если докер — то тут надо следить за тем, что используют программисты и обновлять какой-нибудь базовый image.

Обновлять рантайм — м? В дотнете рантайм не обновляется, если проект сделан под core 2.0, то на нем и запускается всю жизнь, пока лид не решит сделать судьбоносное решение и обновить версию. Что будет сделано путём исправление одного dockerfile. Не вижу, чем должна быть проблема.

Деплоймент будет гораздо быстрее — компилятор быстрее, плюс не нужно тянуть кучи зависимостей типа docker image с OS, сам docker image будет максимально маленький.
И все в этом духе.

Вот не уверен, что компилятор Go быстрее csc.
Обновлять рантайм — м? В дотнете рантайм не обновляется, если проект сделан под core 2.0, то на нем и запускается всю жизнь, пока лид не решит сделать судьбоносное решение и обновить версию. Что будет сделано путём исправление одного dockerfile. Не вижу, чем должна быть проблема.

То есть security upgrades не принято делать в .NET?

Вот не уверен, что компилятор Go быстрее csc.

Можете протестировать. Но я там еще написал, кроме компилятора.
То есть security upgrades не принято делать в .NET?

Видимо, нет.

Я вообще не припомню уязвимости в .net, которые нужно было бы закрывать.

Можете протестировать. Но я там еще написал, кроме компилятора.

А к остальному у меня нет комментариев.
> Я вообще не припомню уязвимости в .net, которые нужно было бы закрывать.

Идеальный .net.
Вот java мы недавно апдейтили. У нас просто принято делать апдейты безопасности (даже не критические, критические мы сразу же обновляем) периодически.

Не, всё-таки бывают: https://www.cvedetails.com/product/43007/Microsoft-.net-Core.html?vendor_id=26


Не знаю, может они образ дефолтный обновляют… Я лично пользуюсь microsoft/dotnet:2.0-runtime, возможно они просто под этот тег пушат рантайм с исправленными уязвимостями, не готов сказать. Кого-то более мелкого версионирования чем 2.0, 2.1. и т.п., по версиям билда там или закрытым уязвимостям я не встречал.

Я вообще не припомню уязвимости в .net, которые нужно было бы закрывать.


Учитывая размер .net… видимо, либо они прошли мимо вас, либо их от нас скрывают.
возьмем этот вопрос с другой стороны. Зачем если можно добиться перфоменса на одном языке… как то в друг использовать другой, надо всех обучить и т.д., в таких случаях перфоменса нет, надо добавить еще одно усложнение…
Зачем если можно добиться перфоменса на одном языке…


Не на всех задачах из JVM или .NET можно выжать сравнимый с Go перфоманс. При этом их использование сильно не всегда это рентабельно в сравнении с Go.

Всегда есть производительность решения * стоимость использования * стоимость поддержки * скорость разработки. В существенном пласте задач результат оценки по этим 4 критериям для Go выгоднее, поэтому его используют.
встречный вопрос, а нужен ли это перфоменс?
если и так все ок, и продукт укладывается в функционал который от него требуют?
Если все и так ок, если продукт укладывается в функционал, который от него требует, и продукт уже работает, и соотношение упомянутых выше 4 факторов приемлемо в текущей ситуации, ни один здравомыслящий человек и не будет инициировать переход на другую экосистему же.

Если в текущем проекте на дотнете вас все устраивает, откуда вообще может взяться желание переписать его на Go?

А вот если перфоманс в паре узких мест не устраивает, или ресурсы, затрачиваемые на масштабирование решения, вылазят за некоторые разумные пределы, начинают задумываться над оптимизацией. И если уж вы на дотнете, из альтернатив, способных на определенный выигрыш, например, в перфомансе, вам доступны, по факту, C, C++, Rust, Go. И вот тут и начинают считать стоимость/простоту реализации, в которой Go, простите, выглядит одним из самых «бескровных» вариантов, т.к. он объективно проще конкурентов в этой нише.

На чём можно сделать лучше — это выбор «идеального мира». В реальном ищут предпочтительный по соотношению «цена/качество» вариант.
Из того, что я видел, обычно начинают выжимать производительность на самом дотнете, а не инициируют переписывание на что-то другое. В ход идет unsafe, SIMD и вот это всё.
Вот и я о том же, что заради одного перфоманса на другой стек не переползают, обычно, ровно до тех пор, пока совокупность проблем не становится неразрешимой внутри локальной экосистемы.
Go и Kotlin — практически диаметрально противоположные языки. Go создан так, чтобы было удобно компилятору. А Kotlin — чтобы было удобно программисту.
только вот со структурами как то странновато сделано в плане наследования.
хотя по своему тоже фича
Это самая необременяющая реализация типа ООП над структурами Си. При относительной дешёвости достигается гораздо лучшее чтение кода.
я все равно не до конца понимаю почему такое странное наследование.
то есть вроде бы откуда уши растут(методы) понятно, но все же.
Наследование странное, вероятно, потому, что его нет… Композиция есть, наследования нету.
а почему не сделали просто добавлением полей в потомке?
вложенность выглядит несколько противоестественно.
Потому что нет никакого потомка, вероятно. Наследования нет, а значит и потомка нет. Есть встраивание типа, и оно именно то, чем кажется.
в некотором роде таки есть.
и в принципе понятно как это работает.
наверное при таком подходе всё даже логично.
ИМХО, достаточно нетривиальное поведение.

Вы так говорите, будто это что-то хорошее
:)

Так ведь с Го невозможно не разобраться, он ведь такой простой, что прочитав за день книжку с основными моментами можно прод писать.
Проблема в том, что многие executives действительно в это верят.
Почему гоферы так радуются единому бинарнику, преподнося его как огромный плюс? (Или почему так не делают любители других компилируемых технологий, вроде C++?) Деплой же обычно автоматизирован, а динамическую линковку когда-то тоже преподносили как решение некоторых проблем. Каков здесь истинный практический смысл?
1. Потому что Go отъедает рынок у python, php, ruby и пр, где нет единого бинарника.
2. Потому что иногда приходится возится с бинарником напрямую, и когда это один файл — это удобно.

Да, в проекте, где CI уже настолько автоматизирован, что нет в нём никаких правок, это преимущество утрачивается.
Потому что Go отъедает рынок у python, php, ruby и пр, где нет единого бинарника.

Это фантазии любителей Go. Python, PHP, Ruby и так для HighLoad не часто использовались. А писать, к примеру, какую-нибудь админку (внутренний проект) с развесистой бизнес-логикой для 1000 юзеров в месяц на Go — это надо сильно упороться.
Go играет на поле Scala, Elixir, Haskell, Rust, C-расширения. Причём первые 3 дают более приятные возможности для программирования.


Потому что иногда приходится возится с бинарником напрямую, и когда это один файл — это удобно.

Зачем с ним возиться напрямую? Вы по FTP что-ли деплоите, как в старые ламповые времена?

Go играет на поле Scala, Elixir, Haskell, Rust, C-расширения.


Го играет, в первую очередь, на поле node.js, и отлично играет, собственно.

Причём первые 3 дают более приятные возможности для программирования.


Scala… ну, как бы, если вы фанат функционального подхода — да, она лучше Go. Однако императив проще в понимании, поэтому функциональное программирование в массах «не взлетает».

Ну, кстати, да. Про Node.js забыл.
А что касается массовости, массам и Go не нужен, потому что для большинства проектов вообще пофиг отвечает у тебя сервер за 100 ms или за 30 ms.

И я про то же, Go — убийца Node.JS, и конкретно у нее он нишу и отжимает.

А что касается массовости, массам и Go не нужен, потому что для большинства проектов вообще пофиг отвечает у тебя сервер за 100 ms или за 30 ms.


Ну, если говорить о «массах», тут да. Просто есть сегмент «визитка магазина с месячным оборотом в 100 тысяч рублей» — там Go не нужен, если честно. Там лучше какой-нибудь «готовый» фреймворк, а то и шаблон юзать (и по барабану, на чем оно).

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

Это, кстати, заблуждение — думать что между сайтами-визитками и хайлоадом ничего нет по середине. В моём понимании, большинство — это куча разнообразных проектов с многомиллионными бюджетами, но при этом не предполагающих особых нагрузок. Если посмотреть правде в глаза, то даже средне нагруженных проекты от силы 1% от веб-приложений наберётся (сайты-визитки я в расчёт даже не беру)
Я бы сформулировал, что если не предполагается нагрузка выше 10 rps в среднем за сутки, и хотя бы 50 rps в пиковые часы, то даже смотреть в сторону Go — совершенно нецелесообразно. Понятно, что запросы сильно разные бывают и цифры ориентировочные, но порядок примерно такой.

А я и не говорю, что посредине ничего нет. Я говорю про то, что у Go ниша — где-то между 10rps в пике и хайлоадом. И в ней он чувствует себя достаточно уверенно (и дело не только в многопоточности).

Я бы сформулировал, что если не предполагается нагрузка выше 10 rps в среднем за сутки, и хотя бы 50 rps в пиковые часы, то даже смотреть в сторону Go — совершенно нецелесообразно.


Ну не только в нагрузке же дело. Я бы сказал, например, что если бэкенд не содержит в себе развесистой бизнес-логики, смотреть в сторону Java или .NET — сомнительное занятие.

Просто с точки зрения языковой среды сильные стороны Go — модель асинхронности и простота экосистемы. Слабые — примитивная система типов. Просто смотрите, что из этого вам больше нужно.

Я бы сказал, например, что если бэкенд не содержит в себе развесистой бизнес-логики, смотреть в сторону Java или .NET — сомнительное занятие.

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


сильные стороны Go — модель асинхронности

Модель асинхронности Go мне, кстати, не нравится, в Erlang/Elixir гораздо интереснее и, на мой взгляд, удобнее.

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


Вот именно потому «микросервисы» и взлетают. Смотри, есть непосредственно фронт (веб-морда или клиентское приложение), есть бэк, который отдает данные этому фронту и принимает от него запросы. И «развесистую бизнес-логику», конечно, можно держать прямо в этом бэке, но делать так не принято. Именно в той вещи, в которую смотрит фронт, что-то тяжелое считать не принято. Для того, чтобы считать что-то тяжелое, есть java-приложения, очереди, мемкеши и прочие относительно автономные вещи, которым самое место за гошным беком. Основная ниша Go — это вот эти инфраструктурные вещи, прокси, если хотите, назначение которых — маршрутизация, аггрегация уже готовых датасетов, некоторые конвертации данных и тому подобное. А для того, что обрабатывает «развесистую бизнес-логику», есть Java (и сотни других инструментов), которая является значительно более «нежным» относительно нагрузки инструментом.

Да, на Java/C# и т.д., да на любом языке «общего назначения» можно и инфраструктурные вещи писать, только делать это чувствительно больнее, чем на Go. И вот там его ниша. При том, что порог вхождения в язык, на самом деле, действительно низкий. Любой мало-мальски адекватный специалист во «взрослом» и «многоцелевом» энтерпрайз-языке может позволить себе изучить Go как дополнительный инструмент для ограниченного круга задач. Вот реально, понять Go проще, чем «вкурить» тот же Java Stream API (а это сильно один ИЗ инструментов из джентльменского набора java-девелопера).

В конечном итоге для внутреннего портала компании, который должен ворочать логику (иначе нафига он вообще), есть сильно более подходящие инструменты, чем Go — есть ASP.NET тот же, в котором есть реально все необходимое для того, чтобы весь этот функционал реализовать. И в этом инструмент хорош, т.к. это фреймворк. И в этом сценарии Go, честно говоря, вообще не нужен.

А вот в момент, когда часть этого портала нужно будет «отзеркалить» или «смаппить» в виде портала, смотрящего наружу… Или если надо будет отдать простенькое API для запроса состояния какого-то элемента системы… Или если вы дорастете до распределенного решения…

Понимаете, ASP.NET — специалист для того, чтобы тупо проксировать наружу один REST-запрос, скорее всего, тупо поднимет еще один инстанс ASP.NET. Вы же согласны, что полученный оверхед принято называть «конским».

Вся приколюха Go — это язык, заточенный на написание инфраструктурных вещей. Бывает развесистая бизнес-логика, и тут Go сливает. Бывает развесистая инфраструктура, и тут уже сливают большинство языков, умеющих работать с развесистой бизнес-логикой.

Модель асинхронности Go мне, кстати, не нравится, в Erlang/Elixir гораздо интереснее и, на мой взгляд, удобнее.


Кхм, несколько разные инструменты.Прям калибр разный, и для разных задач.

Да и в принципе, вот эта подача вида «язык Go умеет простой деплой и приятную модель асинхронности, а вот простой деплой уже 3 месяца умеет C#, а в эликсире прияная асинхронность». Давайте уже «в лоб», не говорить, что фича А встречается в языке Б, а фича В встречается в языке Г. Собственно, изначально при разработке Go так и сказали «в языке нет ничего усраться-прорывного и уникального, и вы тут не найдете ни одной фичи, которую нельзя бы было встретить в других языках». Давайте покажем другой язык с превосходящей комбинацей фич.
НЛО прилетело и опубликовало эту надпись здесь
Тут вопрос в чем.

Императивный подход (если сильно утрировать) — «запишите последовательность действий по порядку в виде команд языка». Собственно, достаточно доступно любому среднестатистическому человеку без существенных отклонений в развитии.

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

Совсем нет. Функциональный подход — "опишите конвейер преобразований".
Соответственно, каждый этап самостоятелен и не лезет в детали реализации других этапов, а просто принимает входные данные и выдаёт свой результат.


Только людей с математическим складом ума сильно меньше.

Эм, хоть это никак не относится к выбору подходов, но я как-то не верю в существование программистов с другим складом ума.

Функциональный подход — «опишите конвейер преобразований».


Хорошо, пусть так. При этом «опишите последовательность действий» по прежнему выглядит проще.

Тем не менее, всё производство давно уже конвейерное. И если вы хотите стабильный код, вам всё равно придётся отказываться от "последовательности действий" и эмулировать конвейер в императиве, наворачивая кучу паттернов. Просто это неудобно по сравнению с ФП, где всё из коробки под это заточено.

Вы потеряли нить разговора.

Началось с «императив проще для понимания». Это вы отрицать перестали и стали упирать на то, что «правильнее».

Правильность — это вещь, вокруг которых можно миллион копий поломать. Проще (в итоге) написать корректный код — да, вероятно, в функциональном подходе. Но проще в понимании — императив.

Я ничего не отрицал, потому что изначально не понимаю, чем описание последовательности действий (процедурное программирование) проще, чем описание конвейера?.. Понятно только, что ООП (описание объектов и их взаимодействия) уже точно сложнее.

Императивный подход (если сильно утрировать) — «запишите последовательность действий по порядку в виде команд языка». Собственно, достаточно доступно любому среднестатистическому человеку без существенных отклонений в развитии.

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


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

Как раз-таки математика у людей с детства, и понять функции совсем нетрудно. У меня знакомый преподает, он никак не может объяснить детям, что значит "присвоить результат функции". Не знакомы они с этим.


Это вам только кажется, что императивщина такая простая. Мои друзья-непрограммисты до сих пор выносятся с записи i = i + 1. И хоть я 100 раз говорил, что равно — это присваивание, а не равно собственно, не понимают. Видимо, отклонения в развитии. Или неправильные шотландцы.


Вот вы сами, вам приятнее руками цикл for писать, или всё же let foo = a.map(|x| x + 1)? Тут ведь страшная формула вместо простого и понятного "создай переменную со значением 0, создай переменную с длиной массива а, создай буфер размера с эту переменную, присвой в первый элемент буфера значение первого элемента массива а, увеличь первую переменную на единицу, проверь, что её значение меньше длины массива а".


Математика была придумана людьми для людей, и основывается на их мышлении (логики). Формальная арифметика это как раз раздел логики, которая является систематизацией обычного человеческого мышления. Императивное программирование — придумана людьми для описания состояния машины, и отражает способ мышления этой самой машины — состояния, регистры, и вот это всё. Считать это более человечным, чем математику, это надо быть уж очень привыкшим к императивщине.

НЛО прилетело и опубликовало эту надпись здесь
Вот вы сами, вам приятнее руками цикл for писать, или всё же let foo = a.map(|x| x + 1)? Тут ведь страшная формула вместо простого и понятного «создай переменную со значением 0, создай переменную с длиной массива а, создай буфер размера с эту переменную, присвой в первый элемент буфера значение первого элемента массива а, увеличь первую переменную на единицу, проверь, что её значение меньше длины массива а».


let foo = a.map(|x| x + 1)? Тут ведь страшная формула вместо простого и понятного


Вот прямо ведь истину глаголете.

Классическая императивщина:
a = 0
while a < 10 {
… do something…
a = a + 1
}

Вы меня простите, конечно, но вот это «let foo = a.map(|x| x + 1)» вообще ни разу не понятнее человеку «со стороны». Считать это простой и очевидной конструкцией — в вас говорит профдеформация.
НЛО прилетело и опубликовало эту надпись здесь
У меня претензии к высказыванию о том, что «let foo = a.map(|x| x + 1)» проще и ближе в понимании неподготовленному человеку, чем «for i := 0; i < 10; i++» или, допустим, «for i < 10».
НЛО прилетело и опубликовало эту надпись здесь
Меня эти вертикальные палки тоже поначалу удивили, поэтому я с вашего позволения немного перепишу:

foo = map (\x -> x + 1) a

Против, ну, например,

List foo;
for (size_t i = 0; i < a.size(); ++i)
foo.push_back(a + 1);

Второе правда проще для неподготовленного человека?

Давайте пример из Go тогда приведем:

var foo []TypeName
for _, item := range a {
    foo = append(foo, item)
}


Блин, ну честно, в самом деле:

map (\x -> x + 1) a версус range a )))

Понимаете, map, foldr, all, find, filter — это все-таки конструкции, которые могут быть очень лишними в некоторых контекстах. Да и порядок исполнения не всегда очевиден.

НЛО прилетело и опубликовало эту надпись здесь
Почему там :=, а чуть ниже =?


Потому что := — сокращенная запись от var имяПеременной ТипПеременной.

чуть ниже =


Потому что чуть ниже переменная не объявляется.

Что вообще значит foo []TypeName?


var имяПеременной []ТипЭлементаСлайса. В чем, собственно, проблема?

Что за append? Мой мозг вот стриггерился на то, что вы присваиваете всему foo целиком, например.


Все верно делаем, местечковая фича.

А вот когда мне в плюсах надо обойти контейнер с конца в начало и сделать это циклом (например, потому, что контейнер не даёт никаких итераторов, и я не могу переписать код в терминах reverse iterator'ов), я начинаю немного нервничать и по 5 раз перепроверять граничные условия, корректность индексации и всё такое.


Вот поэтому в Go и нет богатого выбора контейнеров.
НЛО прилетело и опубликовало эту надпись здесь
Контейнер — это и какая-нибудь матрица из сишного мира, в том числе.


В обсуждении выше под контейнерами подразумевались сущности, как минимум, предоставляющие итераторы.
Вы меня простите, конечно, но вот это «let foo = a.map(|x| x + 1)» вообще ни разу не понятнее человеку «со стороны». Считать это простой и очевидной конструкцией — в вас говорит профдеформация.

Нет, эквивалентом будет


int[] result = new int[a.length];
for (int i = 0; i < result.length; i++)
{
   result[i] = a[i] + 1;
}

Да, это намного менее понятно. Если вам не нравятся вертикальные палки, можно взять JS: let foo = a.map(x => x + 1).

Как раз императивщина проще для людей только потому…
На выходе получаем то что пишем, всякие '=' легко запоминаются, справа получает значение что вычисления слева… это легче объяснить и уложить в голове. А вот что есть функции высшего порядка, которые могут получить функцию на входе, вернуть функцию на выходе, потом передать эту функцию куда-то еще и т.д. сложно объяснять.

императивщина проще объясняется также по другой причине, человек понимает сразу как работает эта шайтан машина, что куда положить и т.д.

а вот ООП и ФП, как раз любому не подготовленному человеку воспринимается очень тяжело, так как уже надо думать не в духе что вижу, то и получаю, а надо думать совершенно другими абстракциями и в голове еще удерживать что там эта шайтан машина делает…

Помню натыкался на статьи, где на западе в универах давали ФП первым языком (вроде схему, но это не точно), вместо устовяшихся C/Pascal/Java/Python, и результаты ничуть не хуже. Могу поискать пруф, если нужно, но пока могу сказать, что это чисто вопрос привычки.


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

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

Я это пишу, так как самому приходится частенько объяснять людям далеким от программирования, как накалякать код на коленке.

С программистами все проще, хотя людям из универа которым вдалбливали ООП и они им упаровались, иногда очень сложно объяснить каррирование и калбеке, с ходу они тяжело читают такой код.
А вот тем кто упаровался ФП, очень тяжело объяснить подходы ООП.

Сужу по своей практике.
С программистами все проще, хотя людям из универа которым вдалбливали ООП и они им упаровались, иногда очень сложно объяснить каррирование и калбеке, с ходу они тяжело читают такой код.
А вот тем кто упаровался ФП, очень тяжело объяснить подходы ООП.

С этим не могу спорить. Собственно, я с того и начал: синдром утенка. Если бы императивщину так не совали навязчиво, такого бы и не было. Думаю, ситуация будет меняться ближайшие 30 лет. Собственно, она уже изменилась настолько, что в насквозь императивные С++ просовывают std::variant и прочие ФП штуковины.

НЛО прилетело и опубликовало эту надпись здесь
Я к тому, что паттерн-матчинг это дефолтная фича, а во всех мейнстрим языках оно только появляется или появилось. В том же C# только в 7 версии пару лет назад. А он ведь еще считается достаточно активно изменяемым.
НЛО прилетело и опубликовало эту надпись здесь
Я говорил про шаг в нужную сторону, не про реализацию.

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

В шарпе слабенький паттерн-матчинг, но хоть какой-то добавили — уже плюс, тут спору нет.

я вот сам больше упаровался по ООП, в функциональном программировании пока не силен. Хотя после 1 попытки изучения Хаскеля… ну что я могу сказать, я в восторге, но пока я склоняюсь к мнению Дядюшки Боба, то есть, они могут сосуществовать вместе.
Конечно. Кстати, неплохая ссылка в тему, спорная, но полезная: github.com/cblp/funlangs
НЛО прилетело и опубликовало эту надпись здесь
Спасибо за ссылку.

Что касается golang, то его синтаксис, его подход далек от простоты, все же это язык для программистов. Но именно для программистов он прост как 2 рубля.

От сюда наверное и хайп вокруг него, особенно когда нужно разрабатывать проекты с большой скорость, в своей нише, да еще и с программистами далекими от 7-10 лет стажа(цифры примерно на бум). Лично этим он меня и подкупает, просто изучить, просто объяснить, ну и бизнес вроде страдать не должен с его скоростью развития, хотя в проде еще не использовал.

Божечки… И сюда таблицу Сыроветского притащили.

человек понимает сразу как работает эта шайтан машина, что куда положить и т.д.

Ага, только это иллюзия понимания… Потом человек попадает на сайд-эффект и "весело" проводит неделю за отладкой в полном непонимании как работает эта шайтан машина.

Я сейчас говорю о людях для которых программирование != профессия, не более. Императивщину понимают в разы быстрее.

Это просто ваше мнение или есть какие-то подтверждения, кроме "Очевидно"?

Наверное мое мнение и своя личная статистика, не более.

А вдруг затык в том, что Вы непонятно объясняете функциональщину? xD

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

Хотя те вещи которые я объясняю они на мой взгляд читабелнее.
Но факт остается фактом… Моя не очень сильная компетенция в данном вопросе может родить непонимание.

Так вещи — это конкретные конструкции. А начинать надо с идей и предпосылок.
Например, мне не встречалось людей, у которых возникали проблемы с пониманием Linux pipes, а это по сути реализация одной из основных идей ФП. Хотя тут можно возразить, что не так много людей знакомы с Linux pipes, но концептуально это всё равно достаточно просто.
Имхо, проблема ФП в том, что многие авторы книг и статей перебарщивают с математической терминологией, чем создают иллюзию, что всё ппц как сложно.

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

Допустим нам надо решить проблему 2+2. Мы можем думать в формате ООП и скормить объекту x,y конструктору, но можем передать аргументы в функцию, а можем просто из функции без параметров вернуть 4.

Как правильно поступить?
В одном из методов нам нужно создать класс отвечающий за инкапсуляцию и т.д…
В другом чистую функцию…
В дгугом просто забить и выполнить задание.

думать по разному сложно, человек ищет одну сторону мышления

Это довольно спорный тезис. Как же разносторонность мышления?


Допустим нам надо решить проблему 2+2.

Плохой пример. В данном случае, нет смысла даже в функции, это просто константа.


В дгугом просто забить и выполнить задание.

Честно говоря, я уже потерял вашу мысль… Изначально Вы писали, что "императивное программирование" интуитивно понятнее. Доминирующий вариант императивного программирования — ООП. Но теперь Вы, похоже, уже согласны, что ООП для человека без спец.подготовки — это сложно.

Пример не удачный, как наверное и любой пример без контекста.

Но скорее я сейчас говорю о том как быстрее и легче решить задачу.

Воспринимать это как объект(ООП), как процесс(ФП), как просто должное и не городить абстракции вокруг задачи(императивное...)?

Это довольно спорный тезис. Как же разносторонность мышления?


разносторонность субъективная вещь на мой взгяд, есть опыт, а он как раз субъективен.

Ради интереса возьмем размышления такого адепта как Егор Бугоенко и его отношением к ООП, но ведь во многих вопросах он прав, но чисто в технических нет(от сюда и так много споров и негодований), какое решение мы применим, скорее всего такое которое нам ближе)
Воспринимать это как объект(ООП), как процесс(ФП), как просто должное и не городить абстракции вокруг задачи(императивное...)?


Маленькая поправочка, не «императивное», а процедурное. ООП-языки в подавляющем количестве случаев императивны.
ООП языки во многом дают возможность решать проблемы императивно, даны инструменты… я к тому за что топит Егор Бугаенко в поисках идеальных ОО языков программирования. Но мыслить как ООП программист и как он будет делать другой вопрос.
Хотя я убеждаюсь в том что лучше мешать ООП и ФП, пока мое субъективное мнение.
Но с другой стороны, легко объяснить не процесс формирования цифр, передачи параметров, а скорее проще объяснить состояние инкаплсулированного стейта в объекте, при всем при этом, легко в голове почти у каждого среднестатистического человека укладывается ограниченный контекст, особенно если предметная область еще не близка.
проще объяснить состояние инкаплсулированного стейта в объекте, при всем при этом, легко в голове почти у каждого среднестатистического человека укладывается ограниченный контекст

Вы рассматриваете какие-то очень тривиальные примеры, оторванные от реальной практики. Спору нет, ООП даёт быструю иллюзию понимания. А осознание того, что оно ложно чуть менее, чем полностью, приходит только с годами опыта.
Попробуйте какие-нибудь простенькие паттерны типа абстрактной фабрики или моста объяснить человеку со стороны.

Ну так ООП и ФП направлены… не верно пишу и говорю, все это направлено на упрощение, на легкую поддерживаемость, не все практику ООП и ФП могут дать легкость понимания кода. Но все мы боремся со сложностью…

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


Есть другая крайность. Человек на чисто-функциональном языке весело проводит две недели, силясь понять, как этого самого сайд-эффекта добиться…
НЛО прилетело и опубликовало эту надпись здесь

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

Я радуюсь прежде всего простоте всей системы сборки в целом. В своё время знатно наплевался, когда пытался просто собрать (иногда модифицировать) в системе сборки опенсорсных проектов на C/C++. Помимо прочего, там еще и жуткий зоопарк.


В итоге, когда все "уже автоматизировано", все, вроде, хорошо. А когда нужно сделать шаг влево или вправо, или же просто внедрить систему сборки в новый проект — начинается ад.


Короче, тут не особо важно, один бинарник или нет, важно, что сборка не вызывает такого количества боли.

Скачайте бинарную софтину для линукса (буквально вчера скачал anydesk, а запустить не смог), а потом поищите отсутствующие библиотеки, тогда будет понятно преимущество статических бинарников.
С этим у меня обычно справляется пакетный менеджер)
А потом, когда у Вас _ВСЁ_ запускаемое будет статическим Вы будете лихорадочно бегать по магазинам скупая оперативную память? Статическая линковка хороша до поры до времени или в спецслучаях.

Времена немного изменились. Раньше действительно было именно так. Сейчас — памяти много больше в любом компе, она заметно дешевле, а количество одновременно запущенных программ изменилось не так сильно (если изменилось вообще), чтобы несколько лишних мегабайт в тех программах, которые написаны на Go, имели хоть какое-то значение.

НЛО прилетело и опубликовало эту надпись здесь
Конечно лучше же тупо выжрать в 5 раз больше памяти аналогичным сервисом на Python.
НЛО прилетело и опубликовало эту надпись здесь
На Си не пишут микросервисы. У вас были опасения по поводу того, что микросервисы на Go могут выжрать дополнительную память. Так вот микросервисы на всём остальном выжрут её гораздо больше.
НЛО прилетело и опубликовало эту надпись здесь
Вы исключение и прекрасно это понимаете.
НЛО прилетело и опубликовало эту надпись здесь
а можно ссылочку на уязвимость языка?
НЛО прилетело и опубликовало эту надпись здесь
Ну, как я и думал, уязвимости в инструментарии, «написанном на...»

К самому языку, опять же, ортогональны. Таких уязвимостей на любой язык натаскать можно. Тем более в контексте противопоставления C — сколько еще раз мы будем слышать чУдную историю про выход за границы массива, неочищенную память и все вот это?

Пока существует только одна реализация — это уязвимости языка.


Вы точно не бредите? Давайте посмотрим на то, что вы показали:

1. directory traversal in «go get» via curly braces in import paths

Чудно, уязвимость в go get. 3 вопроса:
— Вы в курсе, что go get не единственная реализация пакетного менеджера (в конце концов, git делает ровно то же самое)?
— Пусть go get — официальная тулза экосистемы, отличненько. Вам список уязвимостей npm, pip и прочих показать? Или сами отыщете?
— Вас смущает то, что оно собрано внутрь бинаря go. Дык, бинарь go — это не язык, это компилятор, линковщик пакетный менеджер и все вот это. Уязвимости компиляторов других языков так же сами найдете, или погуглить за вас?

2. Вторая чУдная уязвимость «remote command execution during „go get -u“» в том же go get. Те же вопросы повторить?

3. Третья: crypto/x509: CPU denial of service in chain validation

Уязвимость в стандартной библиотеке. Покажите мне уже язык, в котором НЕ находили уязвимости в стандартной библиотеке.
Не первый и не последний софт с уязвимостями. Выпустят патч и всего делов. А вот вы например уверены, что ваши программисты предотвратили переполнение буфера во всех местах. valgrind`ом каждый раз софт прогоняют? На Эльбрусе пробовали запускать, для аппаратного отсечения уязвимостей?
НЛО прилетело и опубликовало эту надпись здесь
Я же говорю, вы приятное исключение. С таким осознанным подходом можно писать на чём угодно хорошо. Даже для Go вы выключили бы статическую линковку и всё было бы хорошо.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
не жря память, HDD и процессор


Ортогонально линковке, например. Рискну предположить, что дело, скорее, в ручном управлении памятью.

Т.е. вы реально готовы к тому, что каждая программа будет тащить копию джавы, Qt или электрона (т.е. Google Chrome)?

И это не говоря о том, что ядро-то одно на всех. Непорядок. Надо каждую программу с ядром в один EFI-бинарник линковать)

Т.е. вы реально готовы к тому, что каждая программа будет тащить копию джавы, Qt или электрона (т.е. Google Chrome)?


В условиях изолированных контейнеров оно именно так и работает, например.

При этом на рантайме java дисковое пространство сэкономить еще как-то можно, слоями контейнера, а вот про процессор и память — тут уж, простите, никак. Каждый запущенный изолированный процесс будет запускать свою java, свою Qt(которая, к слову, достаточно невелика), свой электрон(правда, непонятно, каким он боком в сфере применения Go).

К тому же могу вас порадовать. В случае именно контейнерной сборки без общего предка статическая сборка Go обойдется вам дешевле и в плане дискового пространства, т.к. принесет с собой не всю стандартную библиотеку, а только используемую ее часть, например.
Основная ниша Go — микросервисы. А их принято запускать в изолированном окружении. Т.е. основная фича разделяемых библиотек вида «одну либу слинковать в несколько бинарей» отпадает. Ну не могут два изолированных окружения шарить память между собой.

Поэтому и сравнение динамически-линкованного сишного бинаря со статически собранным Go-шным, мягко выражаясь, некорректное. Вся разница в том, что Go носит все свои зависимости выше libc в себе, а C — линкует их динамически. Сбилдите статический C-шный бинарь и сравните с Go-шным… Вас ждет удивление, вероятно.
Гугл говорит, что Go умеет собирать разделяемые библиотеки.

Когда у меня 100 микросервисов, и в каждом, условно, 5MB общего кода, то это всего пол гига памяти. Учитывая, сколько денег стоит написать 100 микросервисов, что запуск всех 100 на одном сервере это практически невероятная ситуация, и что обычно они запускаются в контейнерах (которые всё-равно помешают использовать общие динамические библиотеки если только не пойти на какие-то дикие танцы с бубном) — статическая линковка не является реальной проблемой для 99.9% проектов.

Красава, например, ППКС.
Тут нечего обсуждать, такого никогда не будет.
Новый гейтс?
64 Гигов хватит всем?
Я про то, что не видно тенденций к тому, что всё запускаемое будет статическим.
Когда «наступит до поры до времени» вы сможете пересобрать без статической линковки, go просто собирает так по умолчанию.
В серьезных проектах на C++ периодически сталкивался с ситуациями (особенно в *nix системах) когда программа «ведет себя странно». В результате анализа выяснялось что по тем или иным причинам на runtime загружается не та версия библиотеки (не из того каталога к примеру). В этом случае монолит — спасение.
С другой стороны иногда осознанно хочется поделить на несколько частей, для компактности обновления, к примеру.
Что есть смысл все свое таскать с собой буквально я не ставлю под сомнение) Удивляет то, что это входит в TOP-5 фич Go, хотя решение очень распространенное.
Видимо, дело в нише, где Go конкурирует со скриптовыми языками, где нет ни Java-jar'ов, ни сборок в стиле .NET
Данный TOP-5 вообще слабо коррелирует с моим пониманием.
Чего стоит хотя-бы наличие одномоментно 2-х пунктов:
Многопоточность из коробки — в языке не просто сделать многопоточность, а очень просто.
Быстрый язык — в виду компилируемой природы и ограниченности синтаксиса вам будет сложно выжирать много памяти и процессорного времени в ваших программах.
Если бы только здесь) Об этом пишут почти в каждой статье, то есть удаляют достаточно много внимания такой, казалось бы, инфраструктурной штуке. Ну какая же разница, грубо говоря: папку копировать или файл?
Я может непонятно выразился.
Дело в том, что если многопоточность реализуется легко, то несколько потоков будут намного более активно выжирать и память и процессор, нежели 1 поток. (на самом деле в Go потоков будет столько-же сколько ядер процессора, а остальная параллельность будет реализована программно)

По факту именно в языке Go столкнулся с тем, что при простейшей разработке подразумевающей распараллеливание процессор выжирается полностью. В результате программа выполняется за значительно меньшее время. Хотя если пересчитать нагрузку на процессор и время выполнения, то видно, что реальное время вычислений на CPU сопоставимо с другими языками, но они используют процессор на 50% (к примеру) и работают в 2 раза дольше.
GOMAXPROCS и всё в ваших руках, регулируйте в нужную сторону.
Мне показалось, что вы привели пример того, что здесь какая-то особенная статья. А я продолжаю о своем)
Любая статья на Хабре — мнение автора различной квалификации. Для оченки качества этого мнения даны различные инструменты.
Оценивать не могу и не горю желанием, а вот докопаться до истины интересно) Ваша версия про сравнение с нишевыми аналогами кажется мне пока наиболее убедительной.
Укажите ваше понимание, я смогу подправить ТОП, если соглашусь.
Не ТОП5, а ТОП1.
Когда нет карт, приходится делать вид, что у тебя есть козыри.

Ну, это одна из причин, почему получает распространение контейнеризация в той или иной форме. И речь не только про docker/kubernetes на сервере, на пользовательском прикладном уровне. Вроде тех же снапов в убунте.

Скорее всего исчезает проблема в решении зависимостей от разных версий библиотек
Зависимости можно положить в подкаталог, например.
Если они действительно решили отказаться от зависимостей, то смысла в подкаталоге нет.
В таком случае, нужно было бы окромя сборщика мусора в бинарник добавлять и линковщик.
Вы конечно правы, но это уже детали реализации. Меня заинтересовала реакция сообщества, будто этот подход решает какую-то наболевшую проблему других технологий. Вот я и спрашиваю: «Неужели раньше нельзя было взять с собой зависимости, просто разместив их в подкаталоге?»
Можно, но можно было забыть скопировать ещё один новый подкаталог. Что регулярно происходит при работе с Dockerfile.
Я не утверждаю, это скорее предположение.
Другие языки или создание такой архитектуры подгрузки библиотек была связана с малым количеством оперативной памяти, по этому скорее отдавали предпочтение загрузить либу с версией 1.0 и 1.1 один раз, вместо того что бы таскать за собой зависимости. Это естественно накладывает своих проблем.

Golang, так как это язык для определенной ниши, создавался при таких условиях что у нас оперативы пруд пруди))), шутка, но так понимаю сейчас такой подход себя оправдывает именно для golang и задач которые он должен решать.
такой надуманный пример.
Допустим у нас есть 3 микросервиса, которому нужна зависимость от библиотеки, библиотека ставит табы(ох уж этот мир javascript, интриги, расследования… факАпы, обнималшкиАпы).

И каждый микросервис требует свою версию, вот тут и возникает проблема…
Так понимаю в golang, опять же, из-за своей ниши решили категорично решить эту проблему. Просто в других языках, именно компилируемых, не пытались занимать именно эту нишу и решать эту проблему. А в go решили ее решить, так как создавался он Google и под свои решения.

Может быть из-за этого…
(хотя может быть в каких-то она и решена)
Неужели раньше нельзя было взять с собой зависимости, просто разместив их в подкаталоге?


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

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

В общем и целом вопрос в комплексности деплоя/доставки. Го проектировался под сетевые сервисы, и конкретно их задачи решает, и решает хорошо. Соответственно, он находится в той же области, что Docker, и решает примерно те же задачи. Отсюда и предпочтение монолитам — принести на сервер цельный бинарный кусок сильно проще, чем настроить деплой, конфигурирование сервера под задачу, настройку, установку зависимостей и прочее развертывание.

Да и собирать монолитные бинарники вас никто не заставляет, по больше части. Достаточно давно уже можно библиотеки собирать и линковать…
Взгляните на node.js. Простенький проект с исходниками в пределах полумегабайта просто при ините для того, чтобы собраться/запуститься докачивает пару-тройку сотен мегабайт своих зависимостей

  1. Текстовый формат действительно менее эффективен, чем бинарный. Любой типичный проект только в сорцах будет весить немало. NPM вроде бы не умеет в дедуплекацию, из-за чего порождает чертовы фракталы. Но это его проблема, а не концепции.
  2. npm init делать не нужно, ведь программист будет копипастить дистрибутив, а не собирать проект на продакшне, как глупец.
  3. Никто не мешает сбандлить JS со всеми зависимостями в один монолитный файл.
  4. Нода у клиента нужна потому, что это рантайм. Суть не поменяется, если вместо скриптовых файлов будут бинарники. Например — линуксовые пакеты (deb), в которых есть информация о зависимостях, которая в идеале должна без проблем разруливаться пакетным менеджером.


Да и доставить на целевую машину 1 монолитный бинарник, как правило, проще

Чем именно это проще? Команда копирования как была одна, так и останется.
Чем именно это проще? Команда копирования как была одна, так и останется.
Мы тупые разработчики нового поколения, когда мы одной командой копирования копируем один файл, мы не стрессуем.
NPM вроде бы не умеет в дедуплекацию, из-за чего порождает чертовы фракталы. Но это его проблема, а не концепции.


Не выгораживайте концепцию. Любая палка — о двух концах. Поэтому просто выпишите на листочке в два столбика pros/cons и решите, что лично для вас и в каких случаях лучше.

К слову, дедупликация npm не поможет. Собственно, проблема экономии места проблеме доставки примерно ортогональна. Проблема не в том, что оно занимает много места, а в том, что его сложнее дотащить до целевой машины так, чтобы оно не сломалось по дороге.

npm init делать не нужно, ведь программист будет копипастить дистрибутив, а не собирать проект на продакшне, как глупец.


Классическое УМВР, ага…

Никто не мешает сбандлить JS со всеми зависимостями в один монолитный файл.


Но никто не избавит от необходимости притащить туда же node.js нужной версии. А потом обновлять…

Нода у клиента нужна потому, что это рантайм.


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

Можете сравнить с тем же pyhon'ом или node'ой. Зависимости вы можете упаковать в один бандл с приложением — для этого у вас есть соответствующие инструменты, а рантайм — хрен.

Т.е. вы можете в процессе деплоя иметь (на выбор): 1 головняк, 2 головняка, 3 головняка. Go предлагает остановиться на цифре 1. Вас это может не устраивать, но это уже вкусовщина. Хотите 2? Ну, есть ключи сборки в Go — отпилить зависимости отдельно, выпилить рантайм и все вот это. Просто по дефолту Go предлагает цифру 1, и это в его нише — отличная цифра.

Суть не поменяется, если вместо скриптовых файлов будут бинарники.


Ну да, для деплоя особой разницы нет, прямо не спорю. Возьмите ту же Java. Помните, 1/2/3-выбери нужное? Вы можете собрать зависимости внутрь jar'а и будете носить 2 куска (рантайм + все остальное), вы можете собрать jar'ник без зависимостей и будете носить 3. А теперь еще пилят (может, уже и допилили) умелку собрать java-рантайм в тот же бинарь, причем только те куски рантайма, которые нужны и получить ровно то, что по дефолту предлагает Go. И тут по барабану, компилируемый ли это язык, или интерпретируемый — вообще не роляет. Роляет только выбор: 1, 2 или 3. При этом, есть конкретные предпочтительные случаи на каждую из 3 цифр, но во всех из них 1 проще, чем 2 или 3.

есть информация о зависимостях, которая в идеале должна без проблем разруливаться пакетным менеджером


Ключевую фразу пометил. На практике есть неразрешимые на уровне пакетного менеджера кейсы.
Не выгораживайте концепцию.

А то у вас половина аргументов выпадет?) Я не против, что вы будете апеллировать к недостаткам Nodejs, но пометку о том, что это такой себе референс все же стоит оставлять. Сами по себе недостатки ноды — это не преимущества Go.

Проблема не в том, что оно занимает много места, а в том, что его сложнее дотащить до целевой машины так, чтобы оно не сломалось по дороге.

В чем именно проблема? Что ломается по дороге, если все необходимое тащится скопом?

Классическое УМВР

Это сюда каким боком? Использовать технологию неправильно и говорить, что она в этом виновата — это такая себе методика сравнения.

Go в одном бинаре носит сразу и рантайм

У Go есть рантайм? Или вы про стандартную библиотеку?

вы можете в процессе деплоя иметь (на выбор): 1 головняк, 2 головняка, 3 головняка.

Эти «головняки» сильно преувеличины.
Зависимости — это не головняк вовсе, а способ организации проекта. Как я уже выше писал, в ноде вам никто не запрещает собирать единый бандл.
Наличие рантайма — это зависит от конкретной технологии. Вполне реально рантайм таскать вместе с конкретным проектом.

Ну хорошие в Go дефолты — это отлично. Но чтобы это было киллер-фичей технологии...)
У Go есть рантайм?


Есть, даже у C он есть. В этих ваших Линуксах, например, libc называется, и даже несколько альтернативных реализаций имеется: glibc, eglibc, libmusl и все вот это. В системе без libc C-приложения не запускаются.

Хотя, в случае C проблемой доставки это назвать сложно, т.к. весь остальной юзерспейс работает ровно поверх системной libc, а значит и собственно linux-окружение без libc работоспособным считаться не может.

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

Есть, конечно, интерпретируемые вещи, вроде той же node.js, python — у них в понятие «рантайм» входит непосредственно интерпретатор. Есть компилируемые Java и C# — для них рантаймом считается ВМ. Одно остается фактом: все то, что общепринято считается рантаймом для перечисленных языков, на целевой системе один хрен работает поверх все того же C-шного рантайма.

Короче, именно рантайм-зависимости Go-бинаря совпадают с C-шными. Весь рантайм, нужный Go поверх, бинарь носит в себе, но это не отменяет того факта, что он есть.

При этом при деплое мы получаем плюшку следующего вида: подавляющее число языков просят какой-то рантайм поверх системного, чтобы запуститься. При этом на этих языках почему-то пишут, а значит таковая зависимость имеет определенные плюшки, нивелирующие необходимость таскать этот рантайм с собой, следить за обновлением версии и т.д. и т.п.

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

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


Собственно, Go — достаточно нишевой язык. Если целые области, где его применять не стОит. И вот конкретно в его нише (сетевые сервисы, контейнеризованные приложения и т.д.) решения авторов языка местами очень хороши (хоть и не без причуд). Как бы, если вам не нравится референс на Node.js, скажите, с кем предлагаете сравнивать, попробую референсить на другую экосистему. Просто именно в нише, под которую Go разрабатывался, монолитный бинарь — действительно фича, и при этом немаловажная.

Сами по себе недостатки ноды — это не преимущества Go.


В контексте сферы применения Go… Кхм… Именно недостатки ноды и есть ключевые преимущества Go. У них ниши очень сильно пересекаются, и проектировался язык именно так, чтобы НЕ наступить именно в ту лужу, в которую села нода.

При этом, фактически, в роли «микросервисных» языков у Go достаточно много и других конкурентов (тупо навскидку: Java, Python, C# — тысячи их), однако, что характерно, ни один из них не разрабатывался изначально с прицелом на сервисную архитектуру, а потому им «есть куда отступать». Для каждого есть сфера, в которой он откровенно лучше Go, и гошные решения в которой будут выглядеть, как минимум, странно. А ноде отступать, честно говоря, некуда… Особенно с учетом ухода автора ноды в Go-разработчики.
В чем именно проблема? Что ломается по дороге, если все необходимое тащится скопом?


На самом деле, дофига чего может поломаться. Даже Go-шный бинарь может поломаться, по факту, если на целевой машине окажется libc «не той марки». Разница исключительно в том, какое количество «точек отказа»… В остальных экосистемах, как правило, их больше.

Тупо навскидку возьмем даже C. У него рантайм-зависимость ровно та же, что у Go. Однако остальные зависимости в C принято размазывать по системе. На целевой машине может оказаться какой-нибудь грязных хак в path, там может оказаться что-то из стандартной библиотеки не той версии, там может оказаться просто какая-то не обновленная версия библиотеки, да все что угодно случиться может.

Без вопросов, для C эта часть «головняка» решаема тупо статической сборкой… Однако, стоп… Чем в этом случае C-шный бинарь, по сути, будет от Go-шного отличаться? По факту, в решении вопроса доставки C не лучше Go. Да, и не хуже, потому что ничего (в плане простоты деплоя) не может показать результаты лучше, чем статически собранный C-шный бинарь под целевую платформу. «Положил, и оно просто работает» — именно этот подход. Прикол в том, что никаких Go-шных специфических бинарников и не существует. Они ничем от статически сбандленных C-шных не отличаются, они и есть C-шные.

А в подавляющем числе прочих конкурентов есть некоторая своя «проблематика».

Ты взял python, запилил в нём venv, проверил, у тебя все работает? Выкуси, на сервере python другой версии.

Ты собрал маленький jar-ник? Не вопрос, какая версия java у тебя стоит?

Ты упаковал исходники node-проекта и lock-файл приложил? Обломись, с сервера нет линка до репозиториев npm, и зависимости не подсосались. Или подсосались, но свежее твоих разработческих, а в них что-то поломали. Или все хорошо, но на сервере нода другая, старше твоей, а в ней что-то поломалось. Или твоя старше, ты не обновился, а сервер обновился, а в новой версии что-то сломалось…

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


Погодите, ваши же слова:
npm init делать не нужно, ведь программист будет копипастить дистрибутив, а не собирать проект на продакшне, как глупец.


«И эти люди запрещают мне ковыряться в носу?» Как так не делать npm init? Где программист будет собирать дистрибутив, и зачем его копипастить? Вы реально считаете, что кодер сбандлит бэкенд на своей разработческой машине, положит полученный, простите за выражение, артефакапт на прод, и это норм?

Насколько я помню, «правильное использование» nod'ы выглядит так:
1. Взять окружение, максимально соответствующее тому, что крутится в проде (но чистое, «голое, если хотите»). На всякий случай заметим, что машина разработчика, как правило, существенно отличается от прод-окружения, поэтому просто сбандлить проект на месте — плохая идея. На сервере тысячу раз все может «пойти не так».
2. Положить в него исходники (именно голые, из репозитория), сказать npm init или yarn или whatever чего вы там еще используете, после этого собрать проект (рекомендуется таки обновлять зависимости). Собственно, лучше иметь 2 идентичных сервера, один из которых — отладочный. На нем и собирать.
3. Оттестировать, что оно собралось и все еще работает.
4. Доставить новую версию на прод (в теории весьма неплохо иметь билд-сервер, и в момент доставки на прод еще раз прогонять тесты).
Да, не init, а install, прошу прощения.

Вы реально считаете, что кодер сбандлит бэкенд на своей разработческой машине, положит полученный, простите за выражение, артефакапт на прод, и это норм?

Да, это так и должно происходить. Билд-сервер собирает, линтит, гоняет тесты, делает пакет, который деплоится на боевой/близкий к боевому тестовый сервер.

Насколько я помню, «правильное использование» nod'ы выглядит так

Не вижу ни единой причины более считать сборку проекта на сервере клиента правильным решением.
Билд-сервер собирает, линтит, гоняет тесты, делает пакет, который деплоится на боевой/близкий к боевому тестовый сервер.


Один нюанс: билд-сервер воспроизводит боевое/близкое к боевому окружение и в нем собирает пакет бандл, который после тестов деплоится «в бой».
Это уже зависит от того, где гоняются тесты. А так — достаточно, чтобы завёлся подходящий SDK.
Java/C#/OtherVM detected!

В смысле, для JVM, .NET Core и других VM-based окружений — норм, без вопросов, так и есть. Оно потому и VM называется, что в изолированной песочнице работает. Для не-VM окружений уже не факт. Docker-based решения не зря цветут и пахнут.
Кросскомпиляторы, например)
А вы отважный…

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

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


1. Рантайм есть всегда.
2. Если вы носите рантайм + зависимости + приложение кучей, то какие у вас есть преимущества перед одним бинарем, кроме, разве что:
а) преимущества в нагрузке на файловую систему (в сторону бОльшей нагрузки: посчитайте нагрузку на дисковый io при копировании 1000 мелких файлов и копирования одного бинаря ровно такого же размера, как суммарно все эти 1000 файлов);
б) неоспоримого преимущества в размере бандла (в бОльшую сторону: при импорте библиотеки в проект в бандл она упадет вся, в статический бинарь — только используемая часть);
в) еще одной фичи размера бандла (опять же в бОльшую сторону: если вы тащите с собой там же рантайм (ВМ или транслятор), он падает в ваш бандл целиком, вместе со всей стандартной библиотекой в довесок).

Ну, т.е. я плавно подвожу вас к мысли, что Go неплохо так экономит дисковое пространство, относительно «конкурирующих предложений».

Если же вы все это не упаковали в артефакт, получите и распишитесь: вы не уверены, что это запустится на целевой машине.
Рантайм есть всегда

Помимо стандартной библиотеки и продуктов жизнедеятельности компилятора, виртуальная машина в составе «рантайма» есть не всегда.

преимущества в нагрузке на файловую систему

Серьезно? Эта проблема действительно актуальна для вас, когда копирование выполняется руками? Ну я не знаю… в тарболл можно положить, если это это не слишком сложно.

там же рантайм (ВМ или транслятор), он падает в ваш бандл целиком

Ничто не мешает прихватить его с собой без инжекции в бандл.

вы не уверены, что это запустится на целевой машине

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


Виртуальная машина есть не всегда, я такого и не утверждал. А рантайм — всегда есть. И его один хрен надо а) носить за собой, либо б) юзать то, что «лежит на месте». «б» — менее надежно, «а» — проще (и дешевле, в конечном итоге, если мы рассматриваем микросервисную модель) делать, когда оно прямо в бинарнике.

Серьезно? Эта проблема действительно актуальна для вас, когда копирование выполняется руками? Ну я не знаю… в тарболл можно положить, если это это не слишком сложно.


Кхм, мы же в контексте микросервисов разговариваем? В нише Go?

Ну вот, значится, список вопросов:

1. Откуда эта маниакальная склонность к ручной работе? То вы копипастите сбандленную на машине разработчика сборку на прод-сервер, то вы «копируете руками» бандл со сборочного сервера на прод… Если ручного копипаста без CI/CD вам хватает, может, вам просто не нужны микросервисы? Может, просто масштаб не тот, чтобы с этим заморачиваться?

2. При доставке на прод-сервер мы имеем 2 значимые по io части: заливку по сети (что кладет нам пропускную способность сети), запись на диск (что кладет дисковый io). Мы помним, мы держим в памяти, что мы в условиях микросервисов, т.е. на целевой машине, кроме вас, еще хренова туча народу (или процессов/контейнеров), и все они пытаются что-то лить в сеть, что-то читать-писать на диск. Да, это может стать затыком.

3. Самое смешное, что решение первой половины проблемы вы сами и предложили — запихать в тарболл, т.е. доставлять одним большим файлом. Осталось понять, каким образом тарболл поможет нам решить вторую половину поблемы — дисковый io. Вы же не собираетесь прямо архив запускать? Т.е. вы его предлагаете слить по сети, а там распаковать. Каким образом это решит проблему «записать 100500 мелких файлов на диск»? Правильно, никак. Как писались, так и писаться будут.

4. Теперь вспоминаем, что общепризнанно считается самым узким местом серверных систем. Точно, дисковая подсистема. Чем реже вы к ней обращаетесь, тем лучше. С точки зрения стоимости ресурса диск, конечно, дешевле. С точки зрения производительности память окупается более эффективно. И вот тут мы вспоминаем, что нам нужно сначала распаковать полученный ранее (по вашей же идее) тарболл (что случается достаточно редко, в процессе деплоя/рестарта, т.е. действительно можно пренебречь до определенных разумных пределом), а потом еще и читать/исполнять то, что мы там на диск понаписали. И вот тут-то и оказывается, что при высокой (и конкуррентной) нагрузке на файловый io сервера читать 100500 мелких файлов — тоже то еще удовольствие. Дисковый кеш поначалу спасает, но он тоже не бесконечный (сильно не бесконечный), и поэтому постоянное чтение постепенно ставит всю систему раком. И вот тут вам приходит мысль: «Мы же офигенно решили проблему доставки по сети, упаковав в тарболл. Вот бы так же с диском, прямо этот тарболл бы и запускать!» И вот прямо в этот момент перед глазами у вас появляюсь я и с торжествующим видом говорю: «Ага! А я что говорил? Говорил же, бери Go! По сути, он именно это и делает — разгружает дисковый io в условиях жесткой конкуррентной нагрузки на диск. И это прекрасно же! А я говорил!»

В общем, надеюсь, суть понятна?)))

Ничто не мешает прихватить его с собой без инжекции в бандл.


А это уже «грабля», простите. Всегда на выходе можно получить ситуацию, что оно собиралось/тестилось не на том, на чем будет крутиться.

Учитывая нацеленность на сервера, этот страх не особо оправдан.


Учитывая серверную (крупно-нагруженно-серверную) нацеленность, любой страх оправдан.
Откуда эта маниакальная склонность к ручной работе?

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

общепризнанно считается самым узким местом серверных систем. Точно, дисковая подсистема.

Один файл — это просто, а сотня (бандл с рантаймом) — это становится сильно сложно. Все относительно, но все же не настолько весомо.

Вы же не собираетесь прямо архив запускать?

Это как WAR'ы? Может и собираюсь.

А это уже «грабля», простите.

В смысле «костыль»?) Настолько же, насколько и статическая линковка для тех же целей, тем более докер.
Откуда эта маниакальная склонность к ручной работе?

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


Ну вот, собственно, времена и изменились. Тем более в контексте CI/CD и микросервисов.

Один файл — это просто, а сотня (бандл с рантаймом) — это становится сильно сложно. Все относительно, но все же не настолько весомо.


Сотня? Хм, вот ща заглянул в текущий проект. ls -f node_modules/* | wc -l Говорит 12956, и в этом вся нода. Теперь вспоминаем, что а) на ноде ворочают бэкенд, б) чтение одного файла по минимуму 2 io-операции, остальное зависит от размера файла и степени вложенности в иерархии файлов. Ну, как бы, нагрузка на файловую систему разнится не то в разы, и даже не на порядки. «Разлет» может достигать «пары тысяч раз».

Это «не настолько весомо» — ну, Г-дь вам судья.

Это как WAR'ы? Может и собираюсь.


Хм, и давно в ноде WAR'ы появились? В Java — видел. Оно, конечно, понятно, что каждая фишка Го в отдельно-стоящем виде встречается в более другом языке, ничего усраться-прорывного в Го нет. Однако аргументация вида «вот эта фича уже есть в языке X, а вот эта — в другом языке, а третья — в третьем». Как бы, для конструктива, определитесь, с чем мы сравниваем, будем рассуждать более детально.

А это уже «грабля», простите.

В смысле «костыль»?) Настолько же, насколько и статическая линковка для тех же целей, тем более докер.


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

А «грабля» — это такая штука, которая может по лбу ударить. Т.е. вероятность «что-то пошло не так» у нее выше, чем у статической линковки.
Сотня? Хм, вот ща заглянул в текущий проект. ls -f node_modules/* | wc -l Говорит 12956, и в этом вся нода. Теперь вспоминаем, что а) на ноде ворочают бэкенд, б) чтение одного файла по минимуму 2 io-операции, остальное зависит от размера файла и степени вложенности в иерархии файлов. Ну, как бы, нагрузка на файловую систему разнится не то в разы, и даже не на порядки. «Разлет» может достигать «пары тысяч раз».
Справедливости ради отмечу, что всё будет закешировано ядром ОС. Но это не повод мириться с этим безобразием.
Еще один нюанс: кеш не бесконечный. Пока проект живет один на физической машине, он закешируется, без вопросов. А вот в условиях, когда таких «небольших проектов» на физическом хосте запущено, предположим, сотня…

Ну и холодный старт никто не отменял. Короче:
а) неочевидно все это;
б) как бы то ни было — лютый писец все это)
> У Go есть рантайм? Или вы про стандартную библиотеку?

Рантайм рантайм — сборщик мусора, планировщик goroutine, etc. Рантайм.
Все это будет в вашем одном бинарном файле.
«Неужели раньше нельзя было взять с собой зависимости, просто разместив их в подкаталоге?»

Даже в таком случае возникают проблемы. Часто они связаны со странным прописыванием переменной PATH на разных машинах. И может оказаться, что тривиальная загрузка библиотеки LoadLibrary(«lib\library.dll») загрузит ее не из текущего каталога программы, а вообще из другой программы.

Потому что, если ты захотел пользоваться своей программой на телефоне, то просто скомпилировал её под arm и закинул файл в телефон. Вот это и есть огромный плюс.

Собрать в apk не один файл будет? Нет?
Собрать можно в deb rpm jar setup.exe и в кучу других пакетов для дистрибуции. Это не проблема и Go не решение. Так зачем этим козырять первым пунктом везде? Важнее ничего нет?

Потому что они программисты, а не админы. Им это всё потом не поддерживать. Допустим, у нас на сервере все демоны написаны на инструментах типа "всё своё ношу с собой". Устанавливать очень удобно, не спорю. Меня вебсервер на go очень выручил однажды, когда я его смог запустить без рута и в очень ограниченной среде на минимизированном линуксе доисторических версий.
Но представьте себе ситуацию: в LTS версии очень популярной libpelmen нашли опасную уязвимость. Нам, админам, требуется:


  1. Просканировать все бинарники в системе на тему наличия в них libpelmen
  2. В найденных случаях проверить, какая именно версия используется
  3. При обнаружении уязвимых бинарников, их нужно расколпаковать, переколпаковать и снова выколпаковать, подложив патченную библиотеку.
  4. Задеплоить полученную версию. Обычно это просто — подменить один файл. Но не всегда.
  5. Перезапустить и проверить, что всё работает.

И так для каждого бинарника с уязвимой библиотекой. К тому же нам, админам, понадобится для go и подобных языков иметь среду для сборки бинарников, и уметь ей пользоваться.
Для сравнения, алгоритм в нынешнем линуксе будет таков:


  1. Посмотреть версию libpelmen в системе. 1 команда.
  2. Если она уязвимая, накатить апдейт. 1-2 команды.
  3. Получить список сервисов, которые от неё зависят, и перезагрузить их. 5 минут работы.
  4. Для особых параноиков, убедиться, что уязвимой версии не осталось в памяти. 5 минут работы.

Так что нафиг такие удобства. Это для специальных случаев, читай: костылей и хаков. Будете поднимать торрент-трекер на утюге — пакуйте всё в один файл.

Потому что они программисты, а не админы.


Вы это сейчас написали потому, что вы админ, а не программист. Правда, ведь?

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


Вот это вы как себе представляете? Часто вы «перепаковываете» бинарники?

Какбэ, варианта-то 3:

1. Приложение доступно в исходниках.

— Пересобираем из исходников, предварительно обновив «багованную зависимость» (работа один хрен не админская, обратитесь к программисту)

2. Приложение не доступно в исходниках (возможно, проприетарное), но доступен автор/правообладатель, т.е. у вас есть возможность постучаться за «поддержкой».

— Стучимся к автору, просим пересобрать бинарь, отдать патченную версию.

3. Приложение недоступно в исходниках, автор шлет лесом/недоступен/помер/хочет много денег.

— Прощаемся с уязвимым софтом либо смиряемся с наличием уязвимого софта на нашем сервере.

Остальное кажется мне достаточно лютой фантазией. Ну, либо путаницей между статическим бинарем и вещами вроде AppImage, Snap и FlatPak. Правда, не понимаю, каким образом что-то из этого вы собираетесь заюзать в качестве системного демона… Ну и, как бы, из всего этого при наличии уязвимости в системной библиотеке «пересобирать» лично вы будете только AppImage, и то, опять же, при отсутствии адекватного доступа к автору.

И так для каждого бинарника с уязвимой библиотекой. К тому же нам, админам, понадобится для go и подобных языков иметь среду для сборки бинарников, и уметь ей пользоваться.


Ребят, по большей части:
а) пересобирать бинари — не ваша забота;
б) именно с точки зрения простоты сборки к go меньше всего претензий (все сведется к паре команд), поверьте, это проще, чем C-шный бинарь пересобрать. Прямо в разы.
Вся речь именно о том, что если везде использовать системы статической сборки, то все бинарники станут «навроде AppImage» и пересобирать их, если что — станет заботой админа.
Смотрите, встречается 2 задачи: «хорошо работать в качестве части системы» и «хорошо работать на любой системе». Задачи не то, чтобы ортогональны, они противоположны. И усидеть на двух стульях нельзя.

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

Вторая… Ну, ее много раз пытались решить, и решение даже примерно найдено: все, что нужно, носить с собой. Выглядит не идеально, но остальные варианты по ряду критериев просто хуже. И вот эта модель — она не для сервисов, демонов, системных библиотек и всего вот этого, она для приложений. Для них AppImage, Flatpak, Snap и все вот это.

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

А про ручную пересборку офисов вместо обновления версии от официального производителя руками админа… Ну, это уже как-то на сказку похоже.

Если же вас беспокоит место на диске. Собственно, когда размер общей кодовой базы дорастает до определенного значимого размера, вполне нормально и «монолитные» решения пилятся на куски. Go вполне позволяет собирать динамические библиотеки, Snap и FlatPak вполне имеют механизм слоев… В случае необходимости патча core-библиотеки, вы просто пересобираете базовый слой. В Snap еще и с плагинами мутились, не уверен, что у них получилось, но оверрайд куска слоя вполне себе пилили. Вероятно, к тому времени, когда это станет критично, допилят.

Поэтому за «демоны» и прочие системные сервисы вы сильно зря переживаете. Впрочем, как и за модули ядра, наборы легковесных утилит и прочие вещи, поставляющиеся в качестве неотъемлемых частей базового дистрибутива. Монолитные сборки — они строго для вещей, не входящих в состав дистрибутива, там они хороши.
>Так а какой безопасности может идти речь, если вы меня не спасли от неверной ручной работы по выделению ресурсов?

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

Дальше не читал, одной вопиющей безграмотности для такой статьи достаточно.

ru.wikipedia.org/wiki/%D0%91%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%B4%D0%BE%D1%81%D1%82%D1%83%D0%BF%D0%B0_%D0%BA_%D0%BF%D0%B0%D0%BC%D1%8F%D1%82%D0%B8
Я не согласен с вашим категорическим тоном, но согласен с замечанием. Утащил ваше замечание в статью.
Она нам как-то не попадалась при поисках, мы попробуем и скажем. Пока добавил в конец статьи.
Тоже выглядит неплохо, добавил.
Go Convey
Вот вам в копилку
Идея интересная, но нет, ибо плохо поддерживается синтаксисом языка. Хотя в статью добавлю.
func TestSpec(t *testing.T) {

	// Only pass t into top-level Convey calls
	Convey("Given some integer with a starting value", t, func() {
		x := 1

		Convey("When the integer is incremented", func() {
			x++

			Convey("The value should be greater by one", func() {
				So(x, ShouldEqual, 2)
			})
		})
	})
}

GoConvey лично мне в первую очередь интересен удобным веб-UI и автоматическим прогоном тестов при изменении файлов в проекте. Довольно удобно держать в браузере открытую вкладку на http://127.0.0.1: порт/ и видеть всплывающее системное уведомление о (не) прохождении тестов каждый раз когда в vim сохраняется файл. Ну и плюс там удобно сразу смотреть покрытие и diff — причём всё это доступно и для обычных тестов, без необходимости писать тесты через Convey().

Мне лично с GoConvey понравилось работать больше всего. И дело далеко не в синтаксисе. Да, синтаксис, не такой приятный как у того же gingko, и привычные BDD идиомы given/before/after и assert'ы вывернуты немного иначе, нежели привыкаешь в других языках (в этом плане gingko гораздо более похож на стандартные реализации). Но к синтаксису, на самом деле, просто привыкаешь со временем и достаточно быстро.


Основная киллер-фича GoConvey — это модель исполнения его каскадов, и она невероятно удобна для жирнющих тестов, где Вам нужно инициализировать кучу моков/стабов а потом прогонять 100500 сценариев с ними. ginkgo же в этом плане заставляет инициализацию выносить в before-блоки, а так как эти блоки являются просто отдельными Go'шными функциями, то сразу рисуется проблема передачи наинициализированного дела в describe- и after-блоки, хоть через внешние переменные, хоть как. В GoConvey же, ты просто об этом даже не думаешь, всё просто работает без всяких чертыханий, ибо определения из внешних каскадов автоматически прокидываются во внутренние по замыканию, а параллельные сценарии выполнения автоматически разделяются на отдельные контексты. Это очень сильно уменьшает шум и бойлерплейт, оставляя в коде теста для чтения строго то, что нужно. Написание таких тестов тоже становится очень приятным делом.


Ну а если соединить GoConvey и httpexpect, то это прямо благодать какая-то для написания E2E-тестов для всяких API'шек.

Мне нравятся такие статьи. Они лишний раз показывают, что Go довольно хороший уже сейчас и уж точно довольно перспективный в будущем.

Авторы, частенько, хитрят и притягивают за уши «непривычности», выдавая их за недостатки:
не нравятся запятые за последним элементом? пишите так:
a := []string{"q"}

и все скомпилируется.

Когда вы пишите о вариантах объявления переменной, так пишите тогда так:
var i uint = 3
j := 6

И тогда станет все на свои места (т.к. есть некоторые действия по умолчанию).

Если вам кажется небезопасным код:
var x map[string]int
x["key"] = 10

так пишите сразу более безопасно:
x := make(map[string]int)
x["key"] = 10

И почему вы не упомянули sync.Map, а сразу так отрезали что «их нет»?

В любом случае, спасибо за проделанную работу. Всегда интересно восполнить знания насчет тонкостей языка, да и критика вполне полезна.
x := make(map[string]int)
x[«key»] = 10

Или
var x = map[string]int{}

или
x := map[string]int{}
Я с вами согласен, отмечу только что:

не нравятся запятые за последним элементом? пишите так:
a := []string{«q»}
Естественно подразумевается списки достаточно длинные по вертикали, не из одного элемента.

Если вам кажется небезопасным код:
var x map[string]int
x[«key»] = 10

так пишите сразу более безопасно:
Дело в том, в статье находятся синтетические скукоженные примеры. В реальном проекте:
* объявление переменной может быть при запуске программы и глобально для некоторого файла,
* выделение для неё памяти — в одной из веток инициализации,
* а присвоение значения на каком-то этапе работы после

Вот выделение памяти может потеряться.

И почему вы не упомянули sync.Map, а сразу так отрезали что «их нет»?
Прошло мимо меня, сейчас добавлю.
В реальном проекте:
* объявление переменной может быть при запуске программы и глобально для некоторого файла,
* выделение для неё памяти — в одной из веток инициализации,
* а присвоение значения на каком-то этапе работы после


Мне кажется, это какой-то плохой проект… Неправильный…
И почему вы не упомянули sync.Map, а сразу так отрезали что «их нет»?

У sync.Map есть один огромный минус и имя ему пустой интерфейс.

Или если все в одном месте, то уж сразу
x := map[string]int{"key": 10}

В этом невинном примере мы «забыли» выделить себе память и получили ошибку времени выполнения.

>Map types are reference types, like pointers or slices
blog.golang.org/go-maps-in-action
Указать автоматически инициализировался nil, что не так?
Ответил выше.
Очень хорошо, что вы подняли эти страшные, ужасные аспекты использования гоу!
Надеюсь, статья повлияет на большое количество человек. Нам, гошникам, не нужна лишняя конкуренция на рынке )
Отсеять заранее несогласных тоже полезно, чтобы хипстеры не набежали.

Как они могут набежать, если они уже все там?

я только недавно начал разбираться с GO, но меня удивляет необходимость переопределять переменную GOPATH, почему нельзя зависимости начинать искать в директории проекта, а потом уже в системных директориях. для меня это загадка
В 1.11 вроде эту проблему решили.

Ну, не сразу. Пока не подправят кучу утилит работать вне GOPATH всё ещё неудобно. Особенно мешает отсутствие gorename, я уже слишком привык к удобному рефакторингу прямо внутри vim. Так что сейчас приходится выкручиваться следующим образом:


  • проект пока остаётся в GOPATH
  • vim запускается с не установленной GO111MODULE
  • команды go test/run/build/mod/… запускаются в отдельном терминале с export GO111MODULE=on

При этом подходе внутри vim корректно работают все вспомогательные утилиты полезные для навигации по коду, рефакторинга, документации, etc. и при этом проект получает все преимущества кеширования тестов/сборки плюс повторяемость сборки на CI и у других разработчиков благодаря использованию модулей.

почему нельзя зависимости начинать искать в директории проекта

вендоринг завезли в го 3 года назад.


меня удивляет необходимость переопределять переменную GOPATH

такой необходимости нет. Нужно всего лишь принять рекомендуемую систему структуры воркспейса.

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

по поводу
Нужно всего лишь принять рекомендуемую систему структуры воркспейса.


Когда только начинается изучения ЯП, модули банальны и на долгое время не задерживаются, а в таком варианте делать эксперименты просто не удобно.

Но так как ситуация изменилась, вопрос снимается. Пойду обновляться)
Извиняюсь, мое упущение, у меня установлен версия 1.10.1.

мой коммент валиден для всех версий за последние два года


модули банальны

я не о модулях, хотя модули очевидно упрощают

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


Собственно, именно так оно и работает. Сначала в vendor текущего проекта ищет, потом в «юзерском» GOPATH, а уже затем в стандартной библиотеке.
НЛО прилетело и опубликовало эту надпись здесь
как мне одним лёгким и изящным движением руки преобразовать мою последовательную программу в параллельную, где список бы обрабатывался чанками по N элементов?
Троллинг защитан. Конечно же без введения специальных типов или специального отношения к типам это не сделать лёгким движением руки. Ну так и на Хаскеле нет работы.

Ну это в 2018-м году, конечно, успех.
Успех для мигрирующих с динамических языков с GIL или с языков с не очень безопасной многопоточностью.

А вот этот вот defer можно как-то передать наружу вызывающему коду?
Нет, тут я подправлю статью. Не буду столь категоричен.
НЛО прилетело и опубликовало эту надпись здесь
ЧСХ, кстати, на хаскеле и подобных куда больше (интересной для меня) работы, чем на Go.
Да, её даже на Си++ куда больше. Go — нишевая вещь всё-таки.

Если не секрет: чем на Хаскеле занимаетесь?
НЛО прилетело и опубликовало эту надпись здесь
А вот этот вот defer можно как-то передать наружу вызывающему коду?

Можно, но без синтаксического сахара:


func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()   // <- примерно таким образом
    // ...
}
НЛО прилетело и опубликовало эту надпись здесь
Да, так делать не надо, но возможность есть.
НЛО прилетело и опубликовало эту надпись здесь

Деструкторы в Go тоже есть: runtime.SetFinalizer. Но на практике они почти не используются.

НЛО прилетело и опубликовало эту надпись здесь
Да, в Go пока есть как бы всё, но половина из этого — некоторый компромисс и работает или не так хорошо или не всегда по сравнению с другими языками.

Давольно активно пользуется там, где cgo. Например imagemagic https://github.com/gographics/imagick/blob/master/imagick/magick_wand.go
Чтобы не бегать по гошному коду и не искать, когда пора высвободить C ресурсы.

НЛО прилетело и опубликовало эту надпись здесь

Пример действительно отличный, поскольку бизнес-фичу запустили быстро, поправив этот биндинг к C коду.
Да и, расскажите, чем добавление интерфейса destroyable + финализатора, дергающего по нему, плохо? Ресурсы управляются, C не течет, клиент о ресурсах не думает, а задача — решена и обрабатывала картинки товаров Lazada года полтора, пока не поменяли на другую библиотеку.

НЛО прилетело и опубликовало эту надпись здесь

Может и зря, вроде хаскелль не сильно в проде распространен, хотя и не молодой язык.

Вы правы, может и зря…

Как всегда, классика: На арену приглашаются Шашечки вёрсус Ехать.
НЛО прилетело и опубликовало эту надпись здесь
Примерно правильно, если с точки зрения идеальной математической модели происходящего. Т.е. в идеальной среде с высококачественными специалистами оно, конечно, лучше на хаскелле. А можно и на C, если хочется побольше производительности.

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

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

Вот и получается, что есть замечательные во всех смыслах гениальные языки, но «ездить» на них в продакшене, чаще всего, становится самоубийством в том или ином смысле.
НЛО прилетело и опубликовало эту надпись здесь
Мне хочется работать с умными прокачанными людьми.


«А работаю, в итоге, я там, где больше платят». Так оно и работает, ага.

А с теми, кто решил войти вайти и вчера закончил обучение в сжатые сроки, не очень хочется.


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

Разработать DSL, компилятор, оптимизатор и статический анализатор для него (чтобы потом другие люди писали более продуктовые вещи на нём, но это, кстати, совсем для восторга не обязательно) — дайте два!


Замечательно! Если вы высококлассный специалист, способный разработать компилятор, статический анализатор и хренову уйму других низкоуровневых вещей — флаг вам в руки, разрабатывайте! Только чего вы потеряли вообще обсуждении Go? Он изначально не подходит вам как инструмент, на нем очень неудобно писать оптимизаторы и DSL'ы. Т.е. инструмент создан НЕ для тех задач, которые вы хотите решать. И он для вас не плох, и не хорош, он вам просто неподходящий.

А если Go каким-то образом залез в ту нишу, в которой работаете вы, то какого, простите, хрена, милчеловек, вы несете всю эту снобскую пургу про то, что вы там DSL, компиляторы и статические анализаторы разрабатываете?

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


У менеджера будут достаточно простые критерии: «денег затрачено» / «денег получено» (чем меньше цифра, тем лучше). Жестоко? Да, жестоко. Но денег, окромя этого менеджера, вам никто не даст.

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


Как, впрочем, и безапелляционность заявлений. Ну и вещи вида «мы не будем рассматривать язык X для нашего проекта, потому что а) он мне не нравится, б) вызывает у меня подсознательное отторжение, в) недостаточно элитарен, чтобы я на нем писал (нужное подчеркнуть)».
«А работаю, в итоге, я там, где больше платят». Так оно и работает, ага.

Во-первых кому что.


Во-вторых я не думаю, что 0xd34df00d делился своими зарплатными ожиданиями с вами, чтобы вы так сравнивали.


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

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


А если Go каким-то образом залез в ту нишу, в которой работаете вы, то какого, простите, хрена, милчеловек, вы несете всю эту снобскую пургу про то, что вы там DSL, компиляторы и статические анализаторы разрабатываете?

Изначально речь шла про то, что в безопасном языке с крутой многопоточностью нужно руками закрывать ресурсы и нельзя легко загрузить M:N многопоточность без оверхеда. Вот и всё.


У менеджера будут достаточно простые критерии: «денег затрачено» / «денег получено» (чем меньше цифра, тем лучше). Жестоко? Да, жестоко. Но денег, окромя этого менеджера, вам никто не даст.

Да, только эта характеристика интегральная за всё время жизни проекта, а не моментальная в текущий момент.


Как, впрочем, и безапелляционность заявлений. Ну и вещи вида «мы не будем рассматривать язык X для нашего проекта, потому что а) он мне не нравится, б) вызывает у меня подсознательное отторжение, в) недостаточно элитарен, чтобы я на нем писал (нужное подчеркнуть)».

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


Фичи языка это не только головная боль при изучении, но и удовольствие при использовании. Убрали их — боль новых разработчиков исчезла, а у существующих прибавилась стократ. Ведь фичей можно просто не пользоваться, а эмулировать её на библиотечном уровне — морока адская.

Во-первых кому что.


Устраиваться на работу не за деньги, простите, сильно смахивает на инфантильность.

Джуны общаются с миддлами, те — с синиорами и так далее. Если разрыв между разработчиками слишком большой, то вместо удовольствия от общения будет одно раздражение.


Это не отменяет того факта, что используемый язык, чаще всего, ортогонален профессионализму разработчика. И противопоставлять «элитарных знающих профессионалов» в «настоящих» языках программирования «быдло-разработчикам» на Go, Node.JS, PHP в конце концов — аргумент вообще не в пользу говорящего, и уж точно основание считать его безграмотным снобом.

Изначально речь шла про то, что в безопасном языке с крутой многопоточностью нужно руками закрывать ресурсы и нельзя легко загрузить M:N многопоточность без оверхеда. Вот и всё.


Мне, почему-то, казалось, что необходимость управления ресурсами — общесистемная проблема, а в функциональным языках еще и болячка…

«и нельзя легко загрузить M:N многопоточность без оверхеда» — вот здесь было бы интересно услышать детали и заодно посмотреть на примеры того, где это реализовано лучше.

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


Мне кажется, возможность писать качественный продукт без учёной степени за душой — это вполне себе плюс инструмента, не?

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


А вот тут намек на синдром утенка проклевывается. Если вы устоявшийся специалист в инструменте А, это естественно, что переходе в экосистему Б вам будет не хватать тех инструментов, которыми вы привыкли пользоваться. Это говорит о том, что экосистема Б хуже экосистемы А? Вообще ни разу. Это говорит только о том, что экосистема Б не экосистема А.

Фичи языка это не только головная боль при изучении, но и удовольствие при использовании. Убрали их — боль новых разработчиков исчезла, а у существующих прибавилась стократ.


Откуда, простите, убрали? Вот не помню, чтобы из языка Go что-то там убирали… Это ваше личное ошибочное суждение. Если в привычном вам языке есть какая-то фича, которой нет в Go, это совершенно не означает, что эту фичу убрали. Ее просто не было.

Ведь фичей можно просто не пользоваться, а эмулировать её на библиотечном уровне — морока адская.


Вот вы и подошли к позиции разработчиков Go. Если фичей не будут пользоваться, значит, ее не будут реализовывать в языке. Вполне логичный подход, имхо.
НЛО прилетело и опубликовало эту надпись здесь
Если на работе H денег платят достаточно, то вы правда предпочтёте работу G, где денег платят сильно больше, даже если там существенно менее интересные проекты?


А в случае, если платят недостаточно? Или вообще в пределах адекватной досягаемости нет ничего, что было бы действительно интересно?

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


Вообще не очевидно. Вы упускаете личностные качества разработчика. Бывают индивиды, которые склонны «расти», и бывают не склонные к этому явлению. И это качество от языка не зависит. Конечно, некоторые экосистемы «тесноваты» для профессионального роста, и «растущие» индивиды имеют свойство их покидать. Даже лично видел пару достаточно ярких примеров. Но вот в Go, на данный момент, еще недостаточно тесно, поверьте.

А вот это вот KeepAlive по ссылке выше в языке с GC — это, извините меня, это полный трындец


Это вы про тот, который из биндинга к C-шной библиотеке… Кхм, странная претензия к языку…

В функциональных языках это скорее...


… не реализуемо в принципе?
НЛО прилетело и опубликовало эту надпись здесь
Это я про тот, ради которого я пошёл в официальную документацию Go и привёл цитату из этой документации Go. Так что к чему эта претензия, как не к языку?


Вот отсюда, видимо: golang.org/pkg/runtime

Это примерно как предъявлять C# за некоторые странности unsafe.

Налагать их по умолчанию и считать тех, у кого эти ограничения разрешились, инфантильными — странновато.


Инфантильными я считаю тех людей, которые пытаются убедить окружающих, что при трудоустройстве ориентируются в первую очередь не на уровень ЗП, а на интересность задачи. Если уровень ЗП достаточен в нескольких местах — велкам, выбираем наиболее интересное из них. Но только и исключительно из тех вариантов, где уровень ЗП достаточен.

а потом говорите о Go так, будто возможности для роста там объективны.


Например, да, объективны. Не менее объективны, чем в любом другом языке, например.

НЛО прилетело и опубликовало эту надпись здесь
Просто, ну, есть определённая культура дизайна языков и их семантики. И некоторые вещи вроде упомянутых выше — это очень странно.


Понимаете, есть непосредственно сам язык Go, и есть его «внутренности», в которые может возникнуть желание «залезть». Вот то, откуда вы привели пример, как раз — это «кишки» (рефлексия, syscall'ы и биндинги к C-шным библиотекам). Приводить куски внутренностей Go как примеры «идиоматичного кода» — такое себе, если честно.
Инфантильными я считаю тех людей, которые пытаются убедить окружающих, что при трудоустройстве ориентируются в первую очередь не на уровень ЗП, а на интересность задачи. Если уровень ЗП достаточен в нескольких местах — велкам, выбираем наиболее интересное из них. Но только и исключительно из тех вариантов, где уровень ЗП достаточен.


Я устраиваюсь именно на интересные задачи. Я выбрал работу на 30к меньше чем мне предлагали в наиболее дорогом офере, потому что мне намного больше понравился другой проект. То ли я инфантильный, то ли меня не существует.

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

Если у меня будет х1.3 доход от текущего моего, я не скажу, что мне будет куда потратить эти деньги. Ну да, смогу почаще в рестораны девушку водить, или там больше игр в стиме покупать. Но я буду тратить больше половины жизни в месте, где мне не так комфортно.

Простая математика: я выхожу на работу примерно в 11, прихожу домой около 21 часов. Занимаюсь своими делами 4-5 часов и ложусь спать. Время на работе + в дороге — 10 часов. время на себя — 4-5 часов. Вы правда предлагаете тупо зарабатывать деньги, когда их некогда тратить? В выходные конфети из них устраивать?

Когда я работал студентом, и на второй работе получил рейз ЗП в 2.5 раза от первого это имело значение. Сейчас же у меня не стоит вопрос выживания, и остается только вопрос получения удовольствия от жизни. Тратить большую часть её в месте где мне некомфортно я бы не стал. Точнее стал бы, но эквивалентная денежная стоимость явно не устроит большинство работодателей, и мы вежливо раскланиваемся в этом случае.
НЛО прилетело и опубликовало эту надпись здесь
Устраиваться на работу не за деньги, простите, сильно смахивает на инфантильность.

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


И да, инфантильно несерьезно подходить к занятию, на которое вы тратите больше половины своей жизни.


Это не отменяет того факта, что используемый язык, чаще всего, ортогонален профессионализму разработчика. И противопоставлять «элитарных знающих профессионалов» в «настоящих» языках программирования «быдло-разработчикам» на Go, Node.JS, PHP в конце концов — аргумент вообще не в пользу говорящего, и уж точно основание считать его безграмотным снобом.

Почитайте про парадокс блаба. Языки, очевидно, находятся на разных позициях в континууме мощности. Чем выше язык по мощности, тем больше возможностей, но тем труднее его освоить. Очевидно, новички начинают с левой части спектра (плюс-минус), и дальше от них зависит, будут они двигаться дальше или нет.


Мне, почему-то, казалось, что необходимость управления ресурсами — общесистемная проблема, а в функциональным языках еще и болячка…

«и нельзя легко загрузить M:N многопоточность без оверхеда» — вот здесь было бы интересно услышать детали и заодно посмотреть на примеры того, где это реализовано лучше.

Я так полагаю имелось ввиду что-то типа a.par_iter().chunks(10).do(sturff)


Мне кажется, возможность писать качественный продукт без учёной степени за душой — это вполне себе плюс инструмента, не?

strawman. Никто не говорит про ученую степень, достаточно пары лет опыта. Зачем выдергиваете слова из контекста? Это некультурно.


А вот тут намек на синдром утенка проклевывается. Если вы устоявшийся специалист в инструменте А, это естественно, что переходе в экосистему Б вам будет не хватать тех инструментов, которыми вы привыкли пользоваться. Это говорит о том, что экосистема Б хуже экосистемы А? Вообще ни разу. Это говорит только о том, что экосистема Б не экосистема А.

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


Откуда, простите, убрали? Вот не помню, чтобы из языка Go что-то там убирали… Это ваше личное ошибочное суждение. Если в привычном вам языке есть какая-то фича, которой нет в Go, это совершенно не означает, что эту фичу убрали. Ее просто не было

Убрали при проектировании. В общем, называйте как хотите, факт остается фактом: в го фич нарочно меньше, потому что так когнитивная нагрузка на изучение снижается. Это не противоречит сказанному, и никак это не опровергает.


Вот вы и подошли к позиции разработчиков Go. Если фичей не будут пользоваться, значит, ее не будут реализовывать в языке. Вполне логичный подход, имхо.

Это здоровый подход. Печально, что го понадобилось несколько лет, чтобы осознать необходимость генериков, и синтаксис им придумали максимально вырвиглазный, ведь еще до создания языка был многолтений опыт, который показывал их необходимость. Но хорошо, что поняли. Ждем теперь статей от адептов, сколько копипаста и кодгена они выкинули с версией 2.0 и как теперь им хорошо живется.

НЛО прилетело и опубликовало эту надпись здесь
Нет. И вообще примерно поэтому подумываю сваливать из большого тырпрайза.


Собственно, из большого тырпрайза валите, видимо, потому, что оно там именно так и работает? )))

некоторые технологии ориентированы на то, чтобы позволить новичкам быстрее дойти до продакшена


Что в этом, собственно, плохого? Понимаете, неработающее гуано, как правило, в продакшен стараются не пускать. Соответственно, языки с низким порогом вхождения рассчитаны на то, чтобы новичок мог родить код, пригодный для продакшена. А сама по себе возможность синтаксиса языка писать зубодробительные конструкции, в которых без пузыря не может разобраться даже тот, кто их писал — весьма сомнительное языковое достоинство.

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

Не, я даже микросервисы не пишу, так что мы не особо пересекаемся.


А вот если бы у нее была шерсть писали, возможно, смогли бы оценить экосистему в целом.
НЛО прилетело и опубликовало эту надпись здесь
Но суть в том, что нельзя сужать критерии выбора работы только оплатой, job security и всяким таким.


Конечно нельзя. Только наличие достаточного уровня оплаты, как бы ни хотелось верить в иное, первичный критерий при выборе работы.

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


Ни один язык в мире не даст вам гарантии того, что рожденные на нем вещи будут поддерживаемы. И порог вхождения тут ни при чем.

Ну я написал целое одно приложение для своего хобби-проекта, которое крутится на сервере и помогает скрейпить те странички last.fm, которые раньше были доступны через API, суммарно там строк 100-150. Это считается за микросервис?


Погуглите SOA, оцените, подойдет ли под модель.

Если да, то я это на том же хаскеле наваял. Первую версию за два вечера сделал, из которых дольше разбирался, как выковыривать из HTML-контента нужные куски. Не знаю, что бы мне там Go предложил.


Как scraper — практически ничего.
НЛО прилетело и опубликовало эту надпись здесь

В хаскелле нет какого-нибудь стандартного парсера?

НЛО прилетело и опубликовало эту надпись здесь
Гарантий-то никто не даст, но это этакий спектр возможностей. И если язык мне системой типов обеспечивает, что тупой рефакторинг ничего не поломает, то такой код поддерживаемее. Или если там KeepAlive тыкать не надо после обращения к ресурсам, как пример.


В Go не надо тыкать KeepAlive. Вы это откуда-то из странного места принесли.

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


Это не значит, что такой код в итоге экономически более оправдан.
НЛО прилетело и опубликовало эту надпись здесь
А как сервер, который запускается, слушает запросы и отвечает на них?


В этом сценарии Go хорош, например. Сильно хорош.
НЛО прилетело и опубликовало эту надпись здесь
Если смотреть чисто в код — получилось бы до смешного похоже, например.

В процессе деплоя на сервер — Go не попросит платформу с собой нести.
НЛО прилетело и опубликовало эту надпись здесь
А если вы мамкин микросервис-писатель, как я, и у вас сервер на генте, например, то вы точно так же написали бы ебилд что для сервиса для go, что для сервиса на хаскеле, и он бы тянул go и прочие зависимости (и, кстати, поддержка конкретно хаскелевских пакетов в генте существенно лучше, насколько я могу судить).


Нету там «go и прочих зависимостей». Философия простая: все внутри.
НЛО прилетело и опубликовало эту надпись здесь
Библиотека для веб-фреймворка? Библиотека для парсинга HTML? Библиотека для автовывода сериализации данных в json?


«Искаропки» в стандартной библиотеке.

Хотя последнее для Go, наверное, перебор.


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


Это потому, что Go-шным «поддержка» не нужна. Вы просто берете бинарь, кладете на сервер, и оно работает.
НЛО прилетело и опубликовало эту надпись здесь
Гента — сорс-бейзд-дистрибутив.


<ЗанудаМоде>Гента не лучший вариант для энтерпрайз-серверов</ЗанудаМоде>

Там всё везде из исходников собирают (хотя можно и binpkg таскать, но это вопреки философии).


Не проблема, собирайте из исходников: очень простой билд-инструментарий в комплекте.
НЛО прилетело и опубликовало эту надпись здесь
А сборка хаскель-пакетов очень простая в генте: натравил специальную тулзу, она из описания пакета сделала ебилд, и всё.


go build проще. Даже натравливать не надо никого. На самом деле, зачем кого-то травить, неполиткорректненько, в самом деле.

НЛО прилетело и опубликовало эту надпись здесь

Надо, когда нет возможности сделать этот defer в вызываемом коде. Возможные ошибки вызывающего кода можно ловить с помощью статических анализаторов, в частности, ситуацию с забытым вызовом cancel() в примере выше они ловят на раз. Но злоупотреблять таким стилем, конечно, не стоит — просто иногда приходится выделять ресурс в вызываемом коде, а освобождать его должен кто-то другой, и обойти это не получается.

Заводить по гринтреду на каждый элемент дорого, так что как мне одним лёгким и изящным движением руки преобразовать мою последовательную программу в параллельную, где список бы обрабатывался чанками по N элементов?


Собственно, либо побить по чанкам ручками (к слову, достаточно недорого в плане производительности, ибо слайсы) и отдать каждый чанк обработчику.
Либо почитать про sync.WaitGroup, если, например, хочется иметь не более N одновременно работающих обработчиков (ладно, уговорил, N мало, лучше пусть будет K)
НЛО прилетело и опубликовало эту надпись здесь
Но это нужно писать самому. Это немножко не соответствует ожиданиям от языка, который заявляет о какой-то прорывной работе с многопоточностью.

Так "прорыв" в том и заключается, что, наконец-то, это можно без проблем написать самостоятельно, это стало достаточно просто, работать оно будет как часы, корректность реализации легко проверяется глазками на ревью плюс встроенным в тесты race-детектором. (Я взял "прорыв" в кавычки, потому что CSP это достаточно старая штука, реализованная задолго до Go в нескольких языках, так что прорывом это считать не совсем корректно, но для мэйнстрима это впервые стало доступно в Go.)


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

НЛО прилетело и опубликовало эту надпись здесь

Конечно. В Limbo я этим пользовался лет 15 назад, а вышел Limbo вообще в 90-х, если не путаю. Но широким массам это стало доступно только когда Go стал достаточно популярен.

Собственно, Go и есть идеологический продолжатель идей именно Limbo, емнип. И авторы одни и те же, и внутри они выглядят подозрительно одинаково.

Limbo сильно проще, за счёт отсутствия POSIX вокруг. Но по производительности Go сильно обогнал Limbo, сил в Go вложили намного больше.

Знаете, а вы правы! Такую штуку с чанками надо добавить в го, но, думаю, на уровне библиотеки, например awg https://github.com/lazada/awg

НЛО прилетело и опубликовало эту надпись здесь

А зачем? Да, согласен, удобно было бы иметь пакет, который принимает массив, по какому числе объектов разбивать или на сколько кусков разбивать, функцию обработки и все. Зачем решать все множество всех возможных задач? Да, го отвратителен, когда хочется общего решения. Ужасен.
Но он прекрасен, когда занимаешься инженерными задачами, но не исследовательскими, и делаешь бизнес штуки.
Может они могли бы быть в чем-то лучше, но… Это и есть главная инженерная задача — искать подходящий компромисс, решающий задачу.

НЛО прилетело и опубликовало эту надпись здесь

Не получается предусмотреть, да.
Golang, на мой взгляд, это история про достаточно хороший инструменты для большинства задач, с которыми можно столкнуться разработчику, работающему на определенный бизнес: Highload, но не realtime; хорошее медианное значение быстродействия, но отвратительные крайние; легко ему обучать, но много однотипного кода; есть какая-то безопасность, но не везде, а только для частых случаев; полная обратная совместимость годами, но мало нововаедений… И так далее. Это инструмент под свои задачи. Немного сьранным будет ожидать от него чего-то иного.

Ну, просто оказывается, что почему-то не получается заранее предусмотреть все варианты.


Вот именно из этого при проектировании Go и исходили. Предусмотреть все варианты на этапе проектирования практически нереально, поэтому язык и предполагает отказ от обобщенного-first подхода. Посмотрите на Java или C++. «Канонический» подход — родить абстракцию, которая удовлетворяет определенным критериям, выделить обобщенные куски реализаций, реализовать эти обобщенные куски, написать конкретную реализацию и уже на этом этапе словить по лбу граблей «в абстракции чего-то не предусмотрели» и уйти в рекурсию, начиная с первого пункта.

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

Поэтому да, Go — инженерный язык, который заточен на получение результата здесь и сейчас… да, местами в ущерб «красоте и выразительности решения», за что «исследователи» его и не любят.

Потому что если у вас есть богатая экосистема с проверенными решениями, вы берете библиотеку Х, подставляете её элементы в качестве генерик-параметров функций библиотеки У и готово. Подлепили где-то UI и немного бузинес-логики и готово.


В го у вас будет бедная стандартная библиотека, и пара пакетов с нвернутыми interface{} повсюду. И я пойму лида, который скажет "нафиг эту непонятную фигню, будем делать свою реализацию". Ну прямо как в плюсах, где не доверяют стандартным коллекциям/строкам/...


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

С библиотеками было трудно года 4 назад, но сейчас, как правило, нужное находится быстро. Про interface {} довольно спорно, как правило их не встретишь в стандартной библиотеке.


Повторюсь, каждой задаче — свой инструмент. И даже Али для микросервисов в одной команде начали пробовать go, хотя до этого унифицицировали всю разработку под свою java.
Java, кстати, как понимаю, на ваш взгляд — это ближайший конкурент go?

С библиотеками было трудно года 4 назад, но сейчас, как правило, нужное находится быстро. Про interface {} довольно спорно, как правило их не встретишь в стандартной библиотеке.

У вас нет языковых средств чтобы сделать удобные библиотеки, вы сами это сказали. Библиотека это и есть то "обобщённое решение", которым гошники жертвуют в угоду "инженерности".


Java, кстати, как понимаю, на ваш взгляд — это ближайший конкурент go?

У го нет конкурентов со стороны языков. Его основная ценность — человек без опыта разработки может сразу начинать кодить. Это большое преимущество для корпорации, которая экономит на инвестициях в человека и сразу получает прибыль, а за чей счет банкет? А за счет бедного человека, который мог бы научиться более удобным инструментам, и решать задачи быстрее, но бизнес его по сути обокрал, как интеллектуально, так и по деньгам, время жизни, затраченное на обход проблемы, которой могло бы и не быть разработчику никто не вернет.


У языка нет задачи, которую он решает лучше/быстрее конкурентов. У него фича в том, что на нем можно сильно сэкономить в ближней перспективе. Помните, старый анекдот?


  • Вы вкладываетесь в обучение сотрудников. А вы не боитесь, что они научатся и уйдут?
  • А вы не боитесь, что они не научатся и останутся?

В общем, если тезисно, го — язык, который позволяет компаниям делать быстрый фигак-фигак и в продакшн. Точнее даже не быстрый, а низкоквалифицированный. Разработчик на C#/Java, да даже C++ справится с задачей в те же сроки. Но разработчика с C# нужно вырастить или дорого купить на рынке, а go-разработчик выпустить продукт не сильно хуже, но намного дешевле. На запуске. Стоимость все равно никуда не денется, и вернется потом, в попытках отлаживать interface{} через interface{}. Но текущие показатели будут отличные, и менеджер получит очередную лычку.


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

Все было бы так, но почему я работал со множеством людей пришедших в го и c++, java, python? Вот недавно познакомился с парнем из rust.
Они все низкоквалифицированные? Или вы способны задуматься и предположить:


  1. Если язык занял определенную долю рынку, значит, он успешео конкурировал за эту долю рынка, значит, у него есть конкуренты.
  2. Если в язык приходят опытные программисты, то у них есть на это причины.
  3. Эти причины явно не подходят к фигак-фигак
  4. Pascal-Modula-Oberon — вам что-то говорит? Если да, то должно вспомниться, что простота языка — это тоже фича и у нее есть причины быть ценной.

P.S. парень с раста ушел кстати из-за того, что проекты на нем превратились в переусложненное… дорогое в долгой поддержке.

Все было бы так, но почему я работал со множеством людей пришедших в го и c++, java, python? Вот недавно познакомился с парнем из rust.
Они все низкоквалифицированные? Или вы способны задуматься и предположить

Может, да, а может и нет. Я не могу судить по "каким-то парням", которые приходятся вам знакомыми.




Я считаю, что гугл продает го и пиарит его по-черному (хуже только с дартом). Мне опять же говорили люди, устраивающие конференции, что гугл буквально сует деньги любому за упоминание этих двух языков. Сам свечку не держал, но почем купил, за то продал.


Ну и о чем речь, если сам Пайк говорил, на кого они ориентировались и какие были цели у языка


The key point here is our programmers are Googlers, they’re not researchers. They’re typically, fairly young, fresh out of school, probably learned Java, maybe learned C or C++, probably learned Python. They’re not capable of understanding a brilliant language but we want to use them to build good software. So, the language that we give them has to be easy for them to understand and easy to adopt. – Rob Pike 1



P.S. парень с раста ушел кстати из-за того, что проекты на нем превратились в переусложненное… дорогое в долгой поддержке.

Не готов ничего сказать, проектов на расте я лично пока не вел. Из того, что писал (немного контрибутил в parity), вроде все не так плохо.

Как мы от вопроса о конкурентах перешли к PR?

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

"У го нет конкурентов со стороны языков"
Я возразил: "Если язык занял определенную долю рынку, значит, он успешео конкурировал за эту долю рынка, значит, у него есть конкуренты"
И… Вы перешли на заявления о проплаченнлм PR и хайпе о го. Не понимаю вашего рассуждения.

Он конкурирует нерыночными механизмами, имхо. Вот и всё, что я хотел сказать, по сути.

Нерыночными… Это как? И у ваших слов есть подтверждение?
Вы написали весьма немало, но пока какого-то обоснования не заметно. Особенно удивляет, что, очень похоже, вы мало знаеме опытных разработчиков на го и их мотивы использования языка.

Нерыночными… Это как? И у ваших слов есть подтверждение?

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

Я планирую следующий проект делать на hyperledger, там как раз го. Тогда смогу более аргументированно говорить.

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

Совсем не знаю, да.

Забавно, у меня сейчас проекты на polkadot и cosmos sdk.
Можем через полгодика сравнить итоги по го и расту.

Примерные пруфы…
Но опять берем в расчет бизнес.
Легкость обучения, легкость сопровождения, легкость входа в проект.
Разве не пруфы?, тяжело сопоставить с другими ЯП, разве минус языка? нет, это огромный плюс, но плюс для кого? для программиста со стажем у которого есть желание и потребность как у инженера повысить свою планку, или у джуна повысить свою зп… зыбки эти холивары
у вас есть богатая экосистема с проверенными решениями


Видели уже. 38 классов коллекций, из которых 12 помечено deprecated, 4 не рекомендуются к использованию, 2 офигенно оптимизированы и потому не рекомендуются к использованию в многопоточной среде, остальные частично дублируют функционал друг друга…

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


Навеяло node.js.
Видели уже. 38 классов коллекций, из которых 12 помечено deprecated, 4 не рекомендуются к использованию, 2 офигенно оптимизированы и потому не рекомендуются к использованию в многопоточной среде, остальные частично дублируют функционал друг друга…

Это какой-то плохой язык. В том же C# всего две deprecated-коллекции, датированные 2001 годом, и в 2003 им вышли замены. Для многопотока те же коллекции с приствкой + Concurrent.


В каком-нибудь расте у вас 0 deprecated-коллекций, для многопотока не нужно никаких дополнительных штуковин, потому что всё работает со стандартными коллекциями + Sync/Send.


Навеяло node.js.

Одно из немногих, что в ноде сделано достойно. Что бы про падлефты не говорили, переиспользование кода это благо.

В каком-нибудь расте у вас 0 deprecated-коллекций


Он просто еще молод.

Одно из немногих, что в ноде сделано достойно. Что бы про падлефты не говорили, переиспользование кода это благо.


Рекурсивные копии всего дерева зависимостей — это благо? Сколько же копий leftpad'ов, в среднем, на проект?
Он просто еще молод.

Это был не единственный пример.

В хачкеле бтв с коллекциями тоже вроде всё ок.

Рекурсивные копии всего дерева зависимостей — это благо? Сколько же копий leftpad'ов, в среднем, на проект?

Копии дерева — плохо.
А вот наличие по пакету на любую хотелку — хорошо.
А вот наличие по пакету на любую хотелку — хорошо.


С пакетами и в Го все примерно хорошо.

Копии дерева — плохо.


А вот эта проблема решена.
Извиняюсь, может влез в диалог не красиво и поспешно.
Но, есть огромное но, это бизнес, не всегда получается удерживать высококвалифицированных программистов, а еще есть задачи которые должны решать менее оплачиваемые программисты, не потому как я этого хочу, но есть просто бизнес. И именно этому бизнесу так удобнее. Golang для ниши serviceSide более успешен. Со своим низким порогом входа, вспоминаю шутку «Программисты делают все что бы они были не нужны», а так же вспоминаю прочитанную историю когда Си программисты считались низкоквалифицированными и Asm было профессионально, а Си уныло и детский сад. Куда катиться бизнес, туда катиться и программирование и спорить об этом бесполезно
ИМХО, самый ужасный недостаток Go — низкий порог входа потому что я хочу работать с людьми способными освоить высокий порог входа.
тут наверное не проблема ЯП, а проблема в бизнесе и Ваших личных потребностях, хотя, и это назвать проблемой сложно.

Мне допустим Go нравится именно этими качествами, то есть простота, возможность более быстро решать проблемы, по крайней мере, пока такое впечатление складывается от изучения.
Вот у PHP тоже низкий порог входа. Вспомнил шутку про PHP и немного дополняю — «На паралимпиаду по программированию приглашаются программисты на 1С, PHP и Go»
Да низкий, но и PHP и GO занимают свою нишу и требования к этим языкам диктуются бизнесом и нишей.

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

это особенность, а не недостаток


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

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

Какой очаровательный юношеский максимализм!

Вы (как и все) хотите работать в таких местах, где бла-бла-бла (вставить произвольную хотелку). А будете в таких местах, где платят деньги.
Что по-поводу пары Java/C#? Go ей ни разу не конкурент, по крайней мере пока он молод (речь про версию Go 1.11).


Вполне себе конкурент, и наверное поэтому гугл переводит свои внутренние сервисы с явы/питона на го, получая прирост производительности.
Может стоит поизучать области применения языка, ознакомиться с успехами и провалами, прежде чем городить подобную отсебятину?
Моё высказывание основано на том, что это два хорошо развитых языка с богатыми возможностями, которые по перформансу сравнимы с Go, а иногда и превосходят. Особого смысла переезжать с них на Go нет. Только если джависты опять наплодили дерево классов глубинной в 20 штук, что нередко бывает, и есть необходимость переписать приложение в варианте попроще и сэкономить гигабайты памяти.
Я сам с удовольствием проснусь в том мире, в котором Rust станет нормой. Но пока он ещё более узко специализирован, чем Go. На Go хотя бы работа есть.
Ну раз зашла речь про работу то вот в C# для мобильных приложений есть Xamarin, для кросс платформенного GUI есть Avalonia для распределенный вычислений с использованием системы акторов есть Akke.net и MS Orleans для игр Unity для Сайтов и микросервисов есть ASP.NET Core (котором можно отключить MVC и все лишнее если вам нужен совсем мелкий микросервис). В стандартной библиотеки есть HttpListener который я сам использовал для написания сетевой части высоко нагруженного микросервиса с нуля. Для работы с БД есть ORM EntityFramework c LINQ. У С# производительность и надежность на уровне Go. По количеству библиотек/тулзов/вакансий превосходит его. Что такого может дать Go чего нет в C#?
Кажется в начале статьи написано, что Go связке Java/C# не конкурент.
Сайтов и микросервисов есть ASP.NET Core


Для микросервисов:
— размер сборки;
— отсутствие необходимости таскать рантайм за собой;
— простая до примитивизма и предсказуемая модель асинхронности;
— порог вхождения;
— отсутствие привязки к Майкрософту (да, не все любят Майков);
— бОльшую стабильность API, обратную совместимость;
— возраст использования в высоконагруженном продакшене.

В остальных областях Go с C# не конкурирует.
— отсутствие привязки к Майкрософту (да, не все любят Майков);

Прекратите нести бред. Может кто — то терпеть не может Google и поэтому не будет использовать Go который Googe продвигает? Ладно, думайте что хотите. Мне все равно. Вместо весомых аргументов какая то мелкая чушь. Глупо с таким как вы спорить и что — то вам доказывать. Вот поэтому я не люблю языки с «низким порогом входа». Там таких как вы много.
Ой, обиделся… Настолько, что кроме одного аргумента, задевшего лично его, остальные шесть предпочел не заметить…

кто — то терпеть не может Google и поэтому не будет использовать Go который Googe продвигает?


Именно! И вот когда вы спросите, какие преимущества есть у C# над Go, одним из пунктов в списке будет «Отсутствие зависимости от Google (Да, Google не все любят)». Это проблема?
НЛО прилетело и опубликовало эту надпись здесь
Подробнее:

У Go есть преимущество (для кого-то значимое) над C#, заключающееся в том, что Go не зависит от корпорации Microsoft.

В свою очередь у C# есть преимущество над Go, заключающееся в том, что C# не зависит от компании Google, которое для кого-то может стать решающим.

При этом у обоих языков есть преимущество над Java — они не аффилированы с Oracle.

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

Не вижу противоречий, собственно.
— отсутствие необходимости таскать рантайм за собой;

  • CoreRT
  • Mono умел бандлиться ещё в 2010

— бОльшую стабильность API, обратную совместимость;

.net core реализует большую часть .net fx, а тому скоро третий десяток лет пойдёт.


— возраст использования в высоконагруженном продакшене.

Предыдущий пункт — на оригинальном дотнете десятилетиями пишут.

— отсутствие необходимости таскать рантайм за собой;

CoreRT


С июня 2018… Отстали на 6 лет.

Mono умел бандлиться ещё в 2010


Собственно, 2 проблемы:

— Mono не полностью совместим с NET Core
— В критичных для бизнеса проектах не любят «альтернативные реализации фреймворков от сторонних разработчиков».

.net core реализует большую часть .net fx, а тому скоро третий десяток лет пойдёт.


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

тому скоро третий десяток лет пойдёт.


А .NET Core (и .NET Standard), еще и одного десятка нет. Цифра, вроде как, ближе к «2 года с момента релиза»… И уже 3-ю версию пилят…

К тому же .NET Framework 3.2, 3.4, 3.5, 4.6 и т.д. — несовместимы между собой. На основании чего ждать иного поведения от .NET Core, так ни разу и не вышедшего в LTS. Первый же, вроде, похоронили уже? А ему 2 года, на минуточку…

на оригинальном дотнете десятилетиями пишут


Вы невнимательно читали заголовок списка. Он для «микросервисов», где Go уделывает .NET-платформу, как Г-дь черепаху. На «оригинальном дотнете» а) не пишут десятилетиями контейнеризованные приложения, б) в принципе не пишут контейнеризованные приложения.

С кором нет никаких проблем, используется в куче высоконагруженных продакшнов. Он был новинкой года 3 назад, и с тех пор давно стал рабочей лошадкой.


Критерии высосаны из пальца.

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

Нет, это именно означает 'большую часть'. WPF / WinForms / WebForms отсутствуют(первые два вернут в 3.0, бета уже вышла) — Core изначально позиционировался как лёгкий серверный рантайм, в котором не было десктопного UI и legacy.


Как .NET FX, так и .NET Core реализуют .NET Standard, под который уже несколько лет таргетятся все мажорные библиотеки на nuget — для них гарантирована совместимость.


— В критичных для бизнеса проектах не любят «альтернативные реализации фреймворков от сторонних разработчиков».

Как-то реальный бизнес прекрасно сидел на Xamarin ещё до покупки Microsoft'ом, который на тот момент разрабатывался командой mono.


К тому же .NET Framework 3.2, 3.4, 3.5, 4.6 и т.д. — несовместимы между собой

  • Внутри мажорных версий — совместимы. 4.0 был выпущен девять лет назад — за 3 года до Go 1.0.
  • Фреймворки автоматически определяются и ставятся sXs, по крайней мере, на windows.
  • Mono имплементирует их все разом, подсовывая чуть разные stdlib.

На основании чего ждать иного поведения от .NET Core, так ни разу и не вышедшего в LTS.

У .NET Core есть LTS.


А .NET Core (и .NET Standard), еще и одного десятка нет.

.NET Standard описывает существующую функциональность, а не описывает новую. Так .NET Standard 1.1, релизнутый в 2016, совместим с .NET FX 4.5, выпущенном в 2012. Большая часть апи, описанных в нём, существует как раз десятилетия.


не пишут десятилетиями контейнеризованные приложения

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


в принципе не пишут контейнеризованные приложения.

Пишут.


  • windows containers существуют уже пару лет в релизном состоянии
  • на mono+docker всё работало ещё в 2015(возможно и раньше, но я тогда с таким комбо впервые столкнулся).
У .NET Core есть LTS.


.NET Core 1 — релизнулся в 2016, LTS-период уже закончился (на дворе 2018-й год).

Прямо по вашей ссылке: 3 года либо год с момента выпуска следующей версии.

Прямого конкурента показать? 5 лет+, в среднем. За деньги — дольше.

Как .NET FX, так и .NET Core реализуют .NET Standard, под который уже несколько лет таргетятся все мажорные библиотеки на nuget — для них гарантирована совместимость.


Поконкретнее можно, что подразумевается под «уже несколько лет». Я же верно понимаю, что «несколько» в вашем понимании = «не более двух»? Странно таргетиться на .NET Standard ДО его выхода, правда же?

Как-то реальный бизнес прекрасно сидел на Xamarin ещё до покупки Microsoft'ом, который на тот момент разрабатывался командой mono.


Прям на серверах сидел? Или, все же, в мобильных приложениях?

Внутри мажорных версий — совместимы.


С docs.microsoft.com:

Если приложение или компонент не работает в .NET Framework 4.5 и в доработанных выпусках, .NET Framework 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1 или 4.7.2 ожидаемым образом,


И ссылка в гайд: что делать, если после обновления платформы «совместимое» с ней приложение вдруг перестало работать

4.0 был выпущен девять лет назад — за 3 года до Go 1.0.


И вы, вероятно, сами сможете назвать причину, по которой он не нашел широкого применения в контейнеризованных окружениях?

Фреймворки автоматически определяются и ставятся sXs, по крайней мере, на windows.


Вот когда k8s сможет рулить windows-нодами, ожидайте взлета популярности .NET Framework 4.0+ (на самом деле нет, конечно, там других концептуальных вопросов хватает)

Mono имплементирует их все разом, подсовывая чуть разные stdlib.


Крутить mono на сервере не принято по очевидным причинам.

.NET Standard описывает существующую функциональность, а не описывает новую.


Рад за него. Собственно, учитывая, что он — спецификация, ничего, кроме «описывать» функциональность он и не может. Вопросы же именно к реализации.

Давайте говорить прямо: реализация .NET Standard пригодная для «верчения» в той среде, куда Go не пускает .NET, впервые анонсирована 2 года назад (.NET Core). Как таковой .NET Core задумывался как «минималистичная серверная реализация» (да, тут согласен), при этом «необходимая и достаточная для верчения ASP.NET» (который сразу проходит мимо ниши Go).

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

При этом основной конкурент, который не пускает .NET на сервера — это НЕ Go. Java — прямой конкурент. При этом если сравнивать тупо языки, C# — гораздо более «стройный» и, главное, более приятный инструмент, чем Java. Что же до рантайма… Хм, JVM уделывает виртуальную машину .NET как Б-г черепаху. Оно и логично, JVM старше и мудрее. При этом недостатки языка Java частично нивелируются тем, что под JVM можно писать сильно не только на одной Java. Недостатки же микрософтовской ВМ, честно говоря, ничем не нивелируются.

.NET традиционно был windows-only инструментом. И буквально 2 года назад майки начали «стремительную экспансию» за пределы windows-экосистемы. Проблема .NET не в том, что он плохой, инструмент достаточно хорош. Проблема в том, что серверная windows жива на весьма ограниченном серверном сегменте.

Так .NET Standard 1.1, релизнутый в 2016, совместим с .NET FX 4.5, выпущенном в 2012. Большая часть апи, описанных в нём, существует как раз десятилетия.


У вас реально с арифметикой плохо, простите. С 2012 года не то что «десятилетий» (во множественном числе) не прошло, одного десятка еще не исполнилось. Ну и, собственно, АПИ без реализации — вещь малополезная. А годная реализация родилась 2 года назад. При этом первую реализацию уже похоронили, текущей — год. Какой популярности вы ожидаете?

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


В коде — никаких. В концепции управления ресурсами — существенные. Собственно, погуглите 12-factor apps — достаточно годный список рекомендаций.

контейнеры, в первую очередь, это просто способ изоляции


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

windows containers существуют уже пару лет в релизном состоянии


Windows Containers на корпоративных windows-серверах то не нужны никому. А вы про серьезное использование в проде…

на mono+docker всё работало ещё в 2015(возможно и раньше, но я тогда с таким комбо впервые столкнулся).


Если оно работало, это совершенно не значит, что так стоило делать.

Да и, собственно, Go для беспроблемного деплоя совершенно не обязателен docker.
Поконкретнее можно, что подразумевается под «уже несколько лет». Я же верно понимаю, что «несколько» в вашем понимании = «не более двух»?
Странно таргетиться на .NET Standard ДО его выхода, правда же?

Не совсем.


MS проанализировали все существующие пакеты nuget перед выпуском .NET Standard и получили, что 98, IIRC, процентов библиотек опираются только на доступные в нём API(понятно, что там могут быть обращения к win-only нативным либам / файлам / etc). По этой причине nuget позволяет использовать пакеты, целящиеся на .NET в .NET Core и .NET Standard, хотя и кидает ворнинг. 'Миграция' для большей части либ заключается в смене таргета в проекте.


У вас реально с арифметикой плохо, простите. С 2012 года не то что «десятилетий» (во множественном числе) не прошло, одного десятка еще не исполнилось.

Именно десятилетий. Большая часть API surface, описанная в .NET Standard, существует с .NET 1.1/2.0, чтобы таргегитьтся по .NET обычно было достаточно просто целиться в основной фреймворк, не трогая win-only части.


Прям на серверах сидел? Или, все же, в мобильных приложениях?

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


И ссылка в гайд: что делать, если после обновления платформы «совместимое» с ней приложение вдруг перестало работать

Да. Потому что мажорные версии гарантируют API surface и то же поведение фреймворка, но не внутреннюю реализацию. Так, несколько раз встречался с тем, что клиентский код переставал работать при обновлении, потому что он лез рефлексией в кишки библиотек, а в новой версии переименовывали поля/приватные методы.


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

LXC, Jail and friends would like a word.


Собственно, погуглите 12-factor apps — достаточно годный список рекомендаций.

Всё это и так применяют — я работал над нагруженным продом, где были микросервисы на дотнете/winserver.

MS проанализировали все существующие пакеты nuget перед выпуском .NET Standard и получили, что 98, IIRC, процентов библиотек опираются только на доступные в нём API


И произошло это в 2016 году. Не было до 2016 года общего таргета .NET Standard, поэтому гарантировать совместимость с оным никто не мог, а гарантии соместимости важны. Да и мультиплатформенный .NET появился тогда же. Собственно, в том и его главная проблема — поздно появился, ниша занята.

Именно десятилетий. Большая часть API surface, описанная в .NET Standard, существует с .NET 1.1/2.0, чтобы таргегитьтся по .NET обычно было достаточно просто целиться в основной фреймворк, не трогая win-only части.


Чудесно. Особенно вот эта часть «обычно было достаточно просто целиться в основной фреймворк». «Обычно», «вероятно» и «возможно будет работать», а также «там внутри все могло поменяться» и «поэтому приложение могло продолжить работать, но не так, как от него ожидалось». Прелестная модель предсказуемой разработки, ага.

Давайте говорить честно, выглядело это как форменный писец. И да, за последние 2 года майки сделали дофига работы, чтобы из этого бардака начала вырисовываться приличная платформа. И оно уже почти выглядит как «готовое решение», но это еще никто не проверил, т.к. а) времени с момента релиза прошло еще слишком мало, б) нет киллер-фичи для переползания с той же Java.

Я верю в светлое будущее .NET, без вопросов — язык симпатичный, ВМ еще починят, а за спиной у него охрененная корпорация, у которой есть деньги на продвижение. Но «взлетит» он несколько позже, пока «молод еще». Ожидайте подъема года через 2-3, не раньше.

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


Потому что мобильное приложение — это не сервер? Если мы уж в контексте Go говорим, именно мобильный сегмент Go у C# вообще не отжимает, нету там Go. Go есть на серверах, и его там достаточно много, и вот туда C# не пускают Go в паре с JVM.

А в остальных нишах C# цветет и пахнет, чо не так то?

Да. Потому что мажорные версии гарантируют API surface и то же поведение фреймворка, но не внутреннюю реализацию. Так, несколько раз встречался с тем, что клиентский код переставал работать при обновлении, потому что он лез рефлексией в кишки библиотек, а в новой версии переименовывали поля/приватные методы.


Ну, как бы, та же проблема возникала вполне себе у разработчиков, которые не лезли своей рефлексией в чужие кишки. Отмаз не засчитан, например.

LXC, Jail and friends would like a word.


Пишите по-русски, английский, видимо, не ваше. Бессмысленная фраза какая-то получилась.

Всё это и так применяют — я работал над нагруженным продом, где были микросервисы на дотнете/winserver.


А чего тогда жалуетесь, что, мол, дотнет недооценен? А, точно, ключевое — дотнете/winserver. До 2017 года дотнет вне вин-экосистемы всерьез не рассматривался в принципе, прчем вполне обоснованно. Ну и чего вы хотели за год, какой популярности ожидали?
Пишите по-русски, английский, видимо, не ваше. Бессмысленная фраза какая-то получилась.

~.


would like a wordустойчивое выражение. Изначально выглядело как 'x would like to have a word with you', но в реальной речи большую часть текста выкидывают, гугл знает. Английский, вообще, достаточно гибок и содержит идиомы, на первый взгляд конфликтующие с грамматикой, вроде классического 'long time, no see'.


Могу на русском перефразировать.


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

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


Рад за них. И за то, что они «не предоставляют средств доставки приложений» — тоже рад. Заодно за то, что они не предоставляют и надежной изоляции тоже.

А средства доставки строятся поверх них (тот же докер, как вы совершенно справедливо заметили). Только вот рассматривать докер как решение для надежной изоляции приложения… ну, как бы так сказать… не надо, засмеют. Он отличный инструмент «изоляции зависимостей», которая служит исключительно целям именно доставки приложений.

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

Ну как бы потому, что безопасный язык лучше не безопасного. Сколько можно уже стек переполнять или обращаться к null ?!

Ну тогда действительно haskell.


Но тезис о "безопасный лучше небезоного" неясен. Лучше когда, почему, какой ценой, когда цена оправдана? Не может же быть ответ "всегда лучше".

Я постепенно прихожу к выводу, что наверное почти всегда лучше. С оглядкой на возможность собрать команду, конечно же.

Скорость запуска продукта? Цена поддержки? Они равны с go?

Это лично мой критерий выбора работы. Бизнес пусть считает в экселе и выбирает.

Понятно, мне стало понятнее ваше мнение.

А почему Раст? Может с асемблером стоило сравнить? Производительность Go сравнивать корректно с питоном или явой, альтернатива именно этим языкам. А с растом можно сравнить скажем по сложности чтения кода и порогу вхождения.
1. Потому что оба языка позиционируются как безопасные.
2. Go — компилируемый язык с легким RTTI, Java — компилируемый язык с виртуальной машиной, а Python — транслируемый язык с виртуальной машиной, поэтому все три сравнивать между собой некорректно.

Хотя конечно Go сравним по перформансу с Java и частично заходит на поле Java, поэтому их приходится сравнивать.
Я наверное как-то пропустил момент про безопасность, мне казалось Го просто язык с простым управлением ресурсами (автоматическая сборка мусора), что сделано не для безопасности, а для простоты и удобства. Мне кажется это основная идиома Го, простота…
Наверное пропустили, это было в начале статье с цитатами про безопасность от самих авторов языка.
НЛО прилетело и опубликовало эту надпись здесь
У go есть определенная область применения, в которой он великолепен. Те же, кто пытаются натянуть сову на глобус представить go в качестве универсального языка, либо не понимают его, либо лукавят. Гвозди и микроскопом можно забивать, только результат печален будет.
Все это к тому, что у вас изначально предвзятое мнение в сторону go, это видно из статьи. Язык это лишь инструмент, и не стоит поливать его, не зная его ниши. Эдак можно про любой язык наворотить.
Ваш комментарий говорит о том, что вы освоили ровно половину статьи. Я указал, что он великолепен в некотором применении, указал, что он не универсальный.
У меня нет предвзятого отношения к языку, он хорош и имеет потенциал стать ещё лучше. Я просто предупреждают тех людей, для которых выразительность языка очень важна.
Я просто предупреждают тех людей, для которых выразительность языка очень важна.

Если б я увидел это в разделе «для кого эта статья», не сказал бы ни слова :)

P.S.
я читаю статьи целиком
Давайте добавим.

Насколько я знаю, Али сейчас эксперементирует с переводом части сервисов с java на go. Так что да, конкуренты в определенных нишах.

RE2 — это не "ограниченное" подмножество PCRE, это очень правильные регулярки, всегда выполняющиеся за предсказуемое время, что полностью окупает отсутствие нескольких фич из PCRE.

Спасибо за разъяснения.
Ваша фраза «полностью окупает отсутствие нескольких фич» является весьма субъективной. Для меня, например, не окупает.

Она кажется субъективной ровно до того момента, когда незначительное изменение во входных данных приведёт к тому, что микросервис ранее обрабатывавший запрос за долю секунды потратит пару дней на обработку этого запроса. Фичастые регулярки в интерактивных приложениях вроде ack/grep/sed/vim — это действительно очень удобно, но вот в микросервисах критично важно избегать такой неопределённости со скоростью выполнения регулярок. В некоторой степени для PCRE проблема решалась чтением Фридла, но, всё-равно, не всегда удаётся на ревью проконтролировать корректность написания всех регулярок, иногда попадаются не очень очевидные случаи… в общем, переход на RE2 и его гарантии реально позволил выдохнуть с облегчением.

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


Ничего из описанного не является проблемой.

НЛО прилетело и опубликовало эту надпись здесь
а во втором языке нужно при вызове каждого метода класса передавать ссылку(или указатель, не помню что такое self в Python)

O RLY?
class A:
   def m(self):
     pass
 
 a = A()
 a.m()  # Где тут нужно передавать ссылку?
Вот это действительно хорошо, сам хотел также сделать, но не вкурил как. Добавил.

Вы забыли упомянуть ещё как минимум один не очевидный момент: nil конкретного типа в интерфейсе.
Из раздражающего лично меня ещё невозможность просто привести срез значений одного типа в срез значений другого (совместимого) типа — я понимаю, из каких соображений нас заставляют рисовать для этого цикл, и даже где-то согласен с ними, но, всё-равно — раздражает.


Но поскольку в Go пока (пока!) нет шаблонов, то очень часто они эмулируются через интерфейсы

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


В языке сущность интерфейса используется, чтобы заткнуть «бедность» синтаксиса языка.

Это единственный момент в статье, который покоробил при чтении. Интерфейсы — один из основных и мощнейших инструментов в Go, наравне с горутинами и каналами. Либо Вы не до конца с ними разобрались, либо это просто неудачный словесный оборот при попытке сказать что иногда для обхода ограничений языка используют конкретно interface{} (и чаще всего этого делать не стоило, обычно есть более правильные альтернативы).


P.S. Кстати говоря, я замечал, что питонисты в Go часто лепят interface{} и далее type switch или type assertion там, где этого нафиг не нужно было делать — это не проблема Go, это проблема мышления разработчика в стиле питона. Примерно как джависты часто по привычке создают много лишних слоёв практически без полезного кода. На Go надо писать в стиле Go, и эти проблемы уйдут.

Вы забыли упомянуть ещё как минимум один не очевидный момент: nil конкретного типа в интерфейсе.
Я не забыл, а не знал, просто не сталкивался.
А в реальном коде для шаблонов обычно используется кодогенерация.
Можете привести пример кодогенерации? Может нам стоит в проекте заюзать.
либо это просто неудачный словесный оборот при попытке сказать что иногда для обхода ограничений языка используют конкретно interface{}
Да это неудачный словесный оборот, подправил.
Что касается интерфейсов, то лично для себя решил, что чем их меньше в коде — тем лучше. Про необходимость избегания type switch согласен.
Что касается интерфейсов, то лично для себя решил, что чем их меньше в коде — тем лучше.


Лучше переформулируйте. Чем меньше в коде пустых интерфейсов, тем лучше — тут можно сразу соглашаться.

А про интерфейсы как таковые — зря вы так, хорошая штука. Вся соль не в том, как они реализованы, а в том, для чего они применяются.

В языке сущность интерфейса используется, чтобы заткнуть «бедность» синтаксиса языка.


Вот тут совсем неправильно, имхо. Нет никакой «бедности синтаксиса». Есть «намеренно примитивная система типов» — вот тут да, это факт, и никто с этим не спорит.

Посмотрите в Java/C#, как и для чего используются интерфейсы там. Вы проектируете интерфейс нужной вам сущности, долго его планируете, вылизываете, приходите к какому-то решению, а затем уже «отливаете в бронзе», т.е. пишете конкретные реализации интерфейса, явно указывая, что, мол, «данный класс — реализация интерфейса X».

Сама «фича» с точки зрения работы с интерфейсами в Go — это отсутствие явного указания того, что структура реализует конкретный интерфейс. Интерфейс-матчинг в Go — с «утиной типизацией».

А делается это для того, чтобы НЕ проектировать интерфейс заранее. И определять его рекомендуется не в пакете с реализации, а прямо рядом с ресивером/потребителем. Т.е. вы не проектируете интерфейс заранее, вы сразу пишете реализацию. И пишете потребителя, работающего конкретно с этой уже существующей реализацией.

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

Подход Го — писать интерфейс ПОВЕРХ уже существующей реализации. Т.е. у вас уже есть работающая реализация, вполне готовая сущность, и какой-то потребитель этой сущности. Если вы решили, что сущности нужна альтернативная реализация — вы просто пишете рядом еще одну, выглядящую аналогично снаружи, и затем рядом с потребителем описываете интерфейс, который нужен потребителю, и которому удовлетворяют обе сущности. Все что вам остается после этого — поменять тип входных параметров в потребителе, и все продолжит работать.

Короче, подход Go к проектированию — сделать код, который будет работать здесь и сейчас, и дать инструментарий максимально удобный для дальнейшей правки архитектуры. Вот в этом он хорош, реально хорош, как ни один из виденных мной языков (хотя, может, я мало видел).
Чем меньше в коде пустых интерфейсов, тем лучше — тут можно сразу соглашаться.
Несомненно. Не пустые интерфейсы вполне себе полезные.

Нет никакой «бедности синтаксиса». Есть «намеренно примитивная система типов» — вот тут да, это факт, и никто с этим не спорит.

Я же писал, я из питона. У меня в питоне есть декораторы, in, контекстный менеджер, __str__ и генераторы. Благодаря чему и веб код выглядит компактнее и ORM не нуждается в кусках SQL для затыкания своей ущербности.
У меня в питоне есть декораторы, in, контекстный менеджер, __str__ и генераторы.


Собственно, вкусовщина, по большей части. Ну и более детально (я не спец в Python'е, могу где-то ошибаться. если что, поправьте):

__str__ — такая штука, которая определяет строковое представление объекта для методов print, str, format и т.д.? Оно?

Вот тут я вас сейчас порадую, в Go можно так же. Есть такая штука — интерфейс Stringer. Другими словами, вам просто нужно для структуры описать метод `String() string` — и вы получите ровно то же самое.

Разница тупо в реализации — в Пайтоне вы перегружаете метод, в Go — реализовываете интерфейс.

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

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

Контекстный менеджер — фактически функция-враппер. Имхо, перекрывается полностью умелками defer'а и наличием замыканий в Go.

Единственное, что могло бы действительно пригодиться — in. И то не понятно, стоит ли заради такой мелочи городить языковую конструкцию. На крайний случай всегда можно обойтись кодогенерацией или рефлексией.

Благодаря чему и веб код выглядит компактнее


Вот этого не понял. Ни разу не видел в веб-коде пайтона… Там же, вроде, `html + js + css`-only?

ORM не нуждается в кусках SQL для затыкания своей ущербности


Ущербность ORM слаба связана с языком, имхо. Тем более, что ORM — объектная реляционная модель. Странно требовать от не-ООП языка аналогичного с ООП-языком удобства работы с объектной моделью. В Go принято, по большей части, не использовать ORM.
Вот этого не понял. Ни разу не видел в веб-коде пайтона… Там же, вроде, `html + js + css`-only?
Имеется код бекэенда веб приложений.
В Go принято, по большей части, не использовать ORM.
Скорее всего вопрос в том, что пока все ORM ущербны. Но если ваш способ `String() string` работает хорошо, то видимо хороший ORM не за горами.
Имеется код бекэенда веб приложений.


Ну тут мы в субьективизм впадаем уже. Мне лично, вероятно, в силу привычки, гораздо проще читать Go-шный код. А от Пайтоновских отступов начинает кровь из глаз течь, и голова болит… Субъективизм как есть: «к чему больше привык».

Скорее всего вопрос в том, что пока все ORM ущербны.


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

Но если ваш способ `String() string` работает хорошо, то видимо хороший ORM не за горами.


Не получится, Go — строго статически типизированный. Тупо String не поможет, смиритесь. Не будет на Go вменяемого ORM'а. Да, собственно, и нужен ли он?
Я писал без ORM на протяжении больших лет, чем с ним. ORM мне не нужен так, как нужен многим молодым разработчикам, потому что они не знаю SQL. ORM нужен для того, чтобы не забыть при переименовании поля сделать это во всех местах.
ORM мне не нужен так, как нужен многим молодым разработчикам, потому что они не знаю SQL.


Ну, как бы, может, молодым разработчикам подучить SQL, что ли… Полезный навык же!

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


Может, простенького query-builder'а хватит, например, на такие случаи? Нафига целый ORM тащить?
Может, простенького query-builder'а хватит, например, на такие случаи? Нафига целый ORM тащить?
Может. Пример покажете?
Честно говоря, конкретно с такими случаями не заморачивался. Навскидку могу squirrel разве что предложить.
github.com/Masterminds/squirrel

Ну и в принципе, вот сюда загляните, тут достаточно много вкусного.
НЛО прилетело и опубликовало эту надпись здесь
Не совсем понимаю, каким образом diff коммита проекта на C++ показывает нужность ORM в Go. Или вы про то, что он нужен «в принципе» и «кому-то»?
НЛО прилетело и опубликовало эту надпись здесь
Можете привести пример кодогенерации?

Я использую https://github.com/cheekybits/genny, довольно удобно. Напр. у нас есть файл queue.go, в котором реализована довольно шаблонная структура очереди, но в ней намертво прошит тип элементов очереди "Msg", пример сигнатуры конструктора:


func newQueueMsg(size int, out chan<- Msg) *queueMsg {}

и нам нужна такая же, но для типов "Event" и "Item" вместо "Msg" — добавляем в начале файла queue.go строку:


//go:generate genny -in=$GOFILE -out=generic_$GOFILE gen "Msg=Event,Item"

запускаем go generate, и получаем новый файл generic_queue.go с конструкторами:


func newQueueEvent(size int, out chan<- Event) *queueEvent {}
func newQueueItem(size int, out chan<- Item) *queueItem {}

Что касается интерфейсов, то лично для себя решил, что чем их меньше в коде — тем лучше.

Тогда рекомендую глубже с ними разобраться, прочувствовать стоящую за ними идею. Это реально базовый элемент, на котором нужно строить архитектуру и внутренние API, который делает жизнь в целом намного легче, а тестирование проще на порядок. Чем больше функций/методов принимает параметрами значения интерфейсных типов (а возвращает при этом обычно значения конкретных типов) — тем обычно лучше. Особенно это касается функций-конструкторов и инверсии зависимостей, когда для создания одних сервисов им нужно параметрами передать сервисы, от которых они зависят, логгер, подключение к БД, etc. — все они должны быть интерфейсного типа. Плюс стоит внимательнее изучить стандартную библиотеку sort, на предмет того, как можно сортировать один и тот же тип по разным критериям простым приведением его к другому типу (Example SortWrapper). И ещё стоит посмотреть на реализацию http.HandlerFunc.

Я не забыл, а не знал, просто не сталкивался.


После прочтения вашей статьи у меня сложилось впечатление, что о Го вы не знаете практически ничего сверх того, что можно узнать за пол часа чтения интернет статей.

Можете привести пример кодогенерации? Может нам стоит в проекте заюзать.


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

Что касается интерфейсов, то лично для себя решил, что чем их меньше в коде — тем лучше


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

Кодогенерация:



На самом деле то еще удовольствие это поддерживать и не забывать обновлять. Фактически ответственность за дженерики переложена на пользователя.

Да простят меня программисты на Go, но последний раз такое отвращение к синтаксису языка я испытывал, когда читал код на PHP лет 5 назад.
Прощаем, так уж и быть, чо.

Рекомендация: не читайте код на Go.
Не читал давно уже, решил интереса ради статью прочитать, посмотреть что да как там. Помимо всех этих проблем возникла ровно такая мысль.
Очень важная реплика. У меня отвращение вызывают тараканы в общественных заведениях. Последний раз видел лет пять назад.

Совпадение? Не думаю.
Неуместный сарказм. Статья про проблемы Go, я выделил ещё одну на свой взгляд.

Не нравится подача информации? Мне ваш юмор тоже не по нутру. Ну а про важность вообще молчу. Впрочем, дело каждого, что писать, забавна лишь самоприменимость вашего комментария.
Объявлять объективной проблемой языка программирования то, что у вас там где-то отвращение на что-то — это определённо заявка на победу в межпланетарном конкурсе на самое раздутое эго.

Но ссылаться завуалированно к какой-то там псевдообъективности в этом ключе и тем более выносить какие-либо оценки мне апеллируя к личности — это однозначная победа в конкурсе главмудаков как минимум этой звёздной системы, поздравляю, с наступающим!
объективной

когда я написал


одну на свой взгляд

Советую внимательнее читать комментарии.


апеллируя к личности

и после


главмудаков

Мне до сих пор непонятно, вы комментарии к своим же комментариям что ли пишете? Я на личности не переходил.

НЛО прилетело и опубликовало эту надпись здесь
vgo одобрен

вот теперь-то можно будет Go, наконец, пользоваться.
и уже в 1.11. Если проект не в GOPATH — по-дефолту модули включены.
Гугл выпустил Гугл.Хром. Яндекс выпустил Яндекс.Браузер.
Гугл следал язык Го. Яндекс сделает язык Я.
… Пусть всегда будет Солнце (Гугл)… Пусть всегда буду я (Яндекс.)…
Нам в Python уже года два как завезли удобные корутины в asyncio, которые работают в эвент лупе, и уже год как завезли статическую типизацию в стандартной библиотеке, с дженериками (мы не переписываем функции для каждого возможного типа)
Очень много людей почему-то не в курсе, что так можно.
Это вы про аннотации что-ли, которые надо самостоятельно в своём коде обрабатывать? Так этож медленно.
Можно обрабатывать, но не обязательно. Этим занимается сторонний тайп-чекер (вроде mypy, который к слову, разрабатывается создателем Python).

Может показаться, что «для этого нужно стороннее решение», но это не так важно, так как mypy — самый используемый тайпчекер, стандарт дефакто и поставляется с любым плагином для среды разработки по Питону (VSCode тот же). В PyCharm есть свой. То есть, проверка типов встраивается очень приятно и без лишних телодвижений.
Если я вызываю метод не напрямую, а предварительно записал его в переменную, эти расширения это поймут?
Поймут.

Вот пример, если я правильно понял ваш вопрос:
# app.py
name = "John"
times = "1"


def greet_times(name: str, times: int = 1):
    for _ in range(times):
        print(f"Greetings, {name}!")


greet_times(name, times)

secret = greet_times
secret(name, times)


mypy app.py найдет и сообщит мне о двух ошибках: как для оригинальной функции, так и для делегированной:
app.py:10: error: Argument 2 to "greet_times" has incompatible type "str"; expected "int"
app.py:13: error: Argument 2 has incompatible type "str"; expected "int"

На самом деле, они мощные и умеют сильно больше, чем пример выше.
Даже если немного начать типизировать код — это помогает. Это еще называют gradual typing.
А если так:
# app.py
name = "John"
times = "1"


def greet_times(name: str, times: int = 1):
    for _ in range(times):
        print(f"Greetings, {name}!")

def greet_times2(name: str, times: str):
    for _ in range(times):
        print(f"Greetings, {name}!")


if newInterface:  # внешнее условие
    secret = greet_times2
else:
    secret = greet_times

secret(name, times)

mypy поможет уже начиная с момента, когда мы попытаемся передать times: str аргуметом в range(...), который ожидает int.


Но если говорить про момент с условием — mypy сообщит, что тут что-то не так:


app.py:19: error: Incompatible types in assignment (expression has type "Callable[[str, int], Any]", variable has type "Callable[[str, str], Any]")

Похоже, тут mypy видит, что одной и той же переменной передаются Callable с разными типами и он сразу же об этом сообщает.


Так же, насколько я понял, mypy делает предположение (так как он не может знать заранее что будет лежать в newInterface), что условие выполнится и в secret будет лежать функция greet_times2, которая на вход принимает str, str и не поднимает дополнительную тревога .


Если же присвоение функций в условии поменять местами (при выполнении условия в secret присвоится greet_times, который str, int), mypy даст знать, что мы еще и типами ошиблись:


app.py:22: error: Argument 2 has incompatible type "str"; expected "int"

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

А GIL в Python уже выпилилили?
Толку то в asyncio если оно на одном ядре крутится?

Вы не путайте asyncio и горутины. Горутины то без проблем по всем ядрам размазываются. И там никаких «ревернсов» с евентлупом не нужны
1. Его никогда не выпилят. Зачем хотеть его выпиливания, если есть Go?
2. Толк есть, IO операции могут распарелиться. Кроме того есть multiprocessing.

Io рараллелить — да. Но все равно на одном ядре и с кучей "реверансов" вокруг isyncio/потоков/процессов.

Первый месяц работы вы будете бороться с компилятором. Потом поймёте его характер и борьба пройдёт. Но этот месяц придётся пережить. Половина хейтеров языка месяц не протянули. Это надо чётко понимать.


Честно говоря не понял что там за борьба нужна???
Поставить Go — элементарно.
Правильно настроить переменные окружения (GOPATH, GOBIN… ) — чуть сложнее и не всегда с первого раза.
А вот после правильной настройки переменных окружения все собирается на ура без каких либо проблем.
go get / go install / go build — просто набрал команду и получил результат.

Если с Сями линковать — да могут быть некоторые сложности, но тут уж извините — С никогда простотой в сборке не отличался и эту свою «непростоту» он и в Go привносит. Тут уж никуда не деться.
Борьба состояит в том, что компилтор постоянно чем-то не доволен, вроде неиспользованной переменной.

я вот использую go build как линтер в редакторе, сразу видно, что и где у меня не используется и все остальные проблемы (хорошо, что компилятор очень быстрый).

Сущая мелочь, например. Особенно в сравнении с компиляторами, например, C или C++.

У меня Vcode (IDE) с расширениями для go. Все косяки подчёркивает красным на записи файла. А запись — по клику мимо зоны редактирования.

Сори это ниже ответ

Публикации

Изменить настройки темы

Истории