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

Как победить дракона: переписываем вашу программу на Golang

Время на прочтение8 мин
Количество просмотров12K
Всего голосов 33: ↑28 и ↓5+23
Комментарии35

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

Простите, а почему бы не сделать один бинарник на Golang, и вызывать нужную вам функцию через параметр?
Например:
<binary-name> config args.json res.json

Тогда как минимум вам не нужно будет дублировать весь рантайм и библиотеки в каждом бинарнике.

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


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


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

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


Во-вторых, простота установки

С использованием контейнеризации этот аргумент выглядит сомнительно


В-третьих, скорость работы

Ну если уж на то пошло то скорость работы Rust или Kotlin Native заметно выше(не на порядок конечно) да и комфорта больше ибо оба языка гораздо богаче в плане фитч, да и инфраструктура тоже если не лучше то эквивалентна голанговской.

«Во первых» тоже отпадает. У k8s есть api, который может работать на любом языке, хоть на php.
Сложно согласиться. Когда проект для широкого сообщества, которое поголовно пишет на Go, и взаимодействует с другими проектами этой экосистемы, вопрос вовсе не в одном конкретном API.

Это только в теории. Есть проблемы с аутентификацией в api например. Ниже ответил развернуто.


В k8s еще есть куча оберток над этим api. Например, shared-informer-ы для слежения за состоянием ресурсов. Эта обертка решает низкоуровневые проблемы и является стандартной для написания kubernetes-операторов. В других языках такого нет, пока сам не напишешь.

Не вникая в проблему, так действительно может показаться, однако реальность чуть сложнее.
Последние две недели я активно работаю с Python Client. Ничем, помимо сгенерированных классов/методов из OpenAPI, он похвастаться не может. Сильно не хватает более высокоуровневых концептов из client-go, а потому велик соблазн забить на Watch совсем и пользоваться только List'ом, несмотря на performance impact. Таких, как Informer, например. Работать напрямую с List/Watch сильно неудобно.

Похожее впечатление было от pyqt. Как бы молодцы, биндинги с классами нагенерили, а за решением проблем всё равно лезешь в C++-ную доку и потом как-то транслируешь примеры кода из C++ в python. В итоге два языка используешь, а не 1. Плюс автодополнение не всё автодополняет, потому что часть свойств в бинаре — удобной разработки! ;)

Инфраструктура — главный аргумент. На Rust не может быть богаче инфраструктура именно для Docker и Kubernetes.


Например, по опыту с Ruby: отсуствие нормальных клиентов для Kubernetes. У нас был самописный, чтобы достучатся до некоторых фич API типа слежения за ресурсами. Самописный клиент привел к тому, что наш dapp не мог коннектится к Google Kubernetes Engine, из-за использования там кастомной схемы аутентфикации. А времени реализовать эту схему в нашем клиенте не было. Вот такого рода проблемы.


Когда перешли на Golang — мы просто включили стандартный клиент kubernetes и все, коннект к GKE из коробки. Если появится что-то новое — сразу будет из коробки.

Вы так уверенно рассуждаете про kotlin-native. Не подскажите, где бы можно посмотреть результаты тестирования KN? А то у меня пока ровно обратная информация.

Если говорить про сравнение с Rust то KN проигрывает, так же как и Го. А вот если сравнивать Го с jvm то тут быстродействие на одном уровне. KN по определению работает быстрее без jvm, темным пятном остается его оптимальная работа с памятью, тут нужно детальное сравнение, которым пока никто не занимался.

KN по определению работает быстрее без jvm

вы это проверяли? или какую-нибудь ссылку дайте.

А вы обратное проверяли? Или какую-нибудь ссылку дайте. Или так и будете на всякие слухи опираться?

Я проверял. KN отставал чуть ли не в 20 раз. Было очевидно что о скорости там ещё даже не задумывались, так как ещё рано об этом думать.

добавлено:
сейчас поискал что-то посвежее: github.com/msink/kotlin-pi
получше, но далеко не так, как вы рассказываете.

Следуя вашей же ссылке:


- C 6.8 sec
- Kotlin/Native interop with C  6.8 sec

Как бы не в х20 раз медленнее
Замеры были сделаны до выхода стабильной версии в апреле прошлого года.


Может и в какой нибудь 0.6 версии и были отставания, я не знаю, но вот к выходу стабильной версии все было подправлено. Компилятор KN опирается на LLVM и это уже о многом говорит.

Вот другое:
github.com/frol/completely-unscientific-benchmarks

Но я согласен, вероятно немного отстал по версиям. Хотя между 0.7 и 0.9 всего ~4 месяца.

Рикну предположить, что команде потребовались считаные дни, максимум недели, чтобы уже начать писать рабочий код на go. На Rust эта цифра измерялась бы на порядок большим сроком. Тут как-то писали об опыте на rust, что через год работы с языком начало получаться писать простые программы сразу, чтобы они компилировались без ошибок...

Злые языки, не верьте :). В языке где нет обобщений и где всего одна конструкция для циклов можно писать быстро, дешево и сердито как на php4. Вот только в Го 2 собрались добавить обобщения, так что халяве пришел конец. Ну а если серьезно я как-то наблюдал мучения команды бывших рубистов при использовании указателей при вызове нативных функций на Го.

Представляюих вероятные мучения в rust...

По этому Kotlin Native в данном случае выглядит куда более привлекательнее. У меня есть другой пример, мой один товарищ по цеху Scala за месяц игры с Rust в перерывах на обед освоил язык и сейчас пишет особо нагруженные сервисы на Rust. Так что, что скалистому хорошо, то рубероиду смерть :) .

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

Ребята, это реально охуенно ;) отсутсвие golang это была единственная реальная причина по которой я в сторону dapp даже не смотрел ;) не хотелось тянуть ruby в экосистему
Ничеси гайки открутили!
Если хотелось просто переписать работающий продукт на другой ЯП ради переписывания — то всё ок. Из трёх пунктов мотивации на переписывание, только первый выглядит адекватным для перехода именно на go. Если важна была скорость работы продукта с минимум затрат на переписывание, то можно было взглянуть на crystal (или elixir) которые имеют ruby синтаксис и семантику. А менять ООП язык на «процедурный» фишка которого concurrency, и не имея в требованиях эту concurrency — звучит странно.
только первый выглядит адекватным для перехода именно на go.

Выше автор уже так и написал:
Инфраструктура — главный аргумент.

Ещё одна фишка Go и аргумент за начало всей этой движухи с переписыванием — кросскомпиляция. Компилятор Go умеет кросскомпилировать статические бинарники без дополнительных телодвижений. Одним заданием в travis ci можно собрать бинарники под несколько платформ (linux+macos+windows).


У Crystal с этим туговато, похоже это не его основное предназначение:


  1. https://crystal-lang.org/reference/syntax_and_semantics/cross-compilation.html
  2. NOTE: Building statically-linked executables is currently only supported on Alpine Linux.


Статические бинарники только под alpine linux. Для сборки динамического бинарника нужно произвести линковку на той платформе, под которую кросс-компилируешь. Не звучит невыполнимо, но заметно сложнее, чем сборка для Go.

Эта фишка свойственна не только Го

Почему не Elixir?
Как минимум (и этого достаточно) — потому что «во-первых» (экосистема Kubernetes).
А зачем рантайм Erlang тянуть (BEAM)?
Почему назвали werf? Какой-то прикол на тему оборотней? Или просто неудачно транлитерировали слово «верфь» на английский? Логика есть в обоих версиях )
Это был долгий процесс… Скоро представим проект отдельной публикацией — там и расскажем! ;-)
Как будто тут много голландцев ;) хотя отсылка на первоисточник — +1 в карму )

Так "верфь" и есть транслитерация слова werf, а не наоборот ;)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий