Comments 97
Спасибо за интерес к деталям нашего выбора! Позвольте пояснить мой подход более развернуто:
1. О выборе языков в принципе
В профессиональной разработке существует 4 основных пути выбора языка:
✓ Личные предпочтения технического руководства
✓ Корпоративные стандарты и комплаенс
✓ Популярные заблуждения ("все пишут на X")
✓ Осознанный выбор под конкретные требования
Я выбрал последний путь.
2. О распределении языков в нашем проекте
Zig: для низкоуровневой части (модификация C-программы)
Идеальная совместимость с C ABI
Контроль памяти без сложностей Rust
Минимальные накладные расходы
Go: для вспомогательных сервисов
Удобен для concurrent-задач
GC не критичен для логирования
Быстрая разработка
PHP: основной бэкенд
Только немного подрпавил, так как удовлетворяет требованиям
3. О философии выбора
Я принципиально не утверждаю, что:
✓ PHP/Python "хуже"
✓ Zig/Rust "лучше"
Каждый язык имеет свою нишу:
Когда нужен контроль памяти — берем Zig/Rust
Когда важна скорость разработки — Go/Python
Когда работает legacy — не ломаем без нужды
Каждый случай выбора языка под проект заслуживает отдельного анализа. В моём сценарии:
✓ Модификация C-кода → Zig
✓ Высокоуровневые сервисы → Go
✓ Основной бэкенд → PHP
почему раньше был отдельный процесс на каждое vpn-соединение, а теперь один процесс для всех?
Вероятно моя формулировка в статье создала неверное понимание происходящего. Давайте разберём архитектурные изменения подробней.
1. Как было раньше:
На каждое подключение создавался отдельный процесс PHP
В каждом процессе загружалась вся кодовая база скриптов
Плюс работал основной процесс ocserv-worker
→ Двойная нагрузка на систему
2. Как сейчас:
Вся бизнес-логика встроена непосредственно в процедуру авторизации
Никаких дополнительных процессов не создаётся
Модифицированный ocserv-worker обрабатывает всё сам
P.S. Если бы я разрабатывал систему с нуля сегодня — возможно, выбрал бы другие инструменты. Но профессиональный подход — это работать с текущими реалиями, а не гнаться за мейнстримом
Приложите, пожалуйста, хотя-бы ссылку на то, что конкретно понимаете под APL, поскольку гугл выдаёт не то. Лучше, конечно, сразу текст, в самом начале статьи, но и ссылка, натянутая на аббревиатуру подойдёт.
Относительно же перехода с одного на другое, даже несмотря на то, что я никогда не был любителем php5, а код на zig мне в принципе нравится больше, всё это пока напоминает смену одной боли на другую.
Вы правы - это действительно смена одного типа сложностей на другие. Только раньше сложности были вроде 'почему empty("0") == true', а теперь - в необходимости явно описывать обработку ошибок. Как-то так получилось, что второй вариант приводит к стабильной работе системы... Странное совпадение, да? Хотя если для вас разница между хронической болезнью и здоровыми нагрузками действительно неочевидна - тогда да, просто "другая боль".
Насчёт APL всё правильно нашли.
А теперь о вреде бизнесу: для поддержки этого решения потребуется знание Zig. Хабр.Карьера: 134 программиста на Zig, 12000+ Golang, 92000+ C.
О, статистика — это святое! Давайте тогда вернёмся к истокам: изначально проект был на PHP, где разработчиков — как песчинок в Сахаре. И что? Он "еле работал", а поддержка напоминала игру в "исправь один баг — получи два новых". Но зато специалистов много, да? Может, проблема не в языке, а в том, что хороший код пишут не толпы, а те самые 134 человека, которые хотя бы понимают, что делают?
Ну а если серьёзно — Zig выбрал не я один. Bun.sh (который рвёт Node.js по производительности), Uber (да, тот самый) и TigerBeetle (который обгоняет InfluxDB) используют его там, где важны контроль над памятью и отсутствие неожиданностей. Но да, конечно, можно и дальше верить, что "много программистов = хорошо'". PHP-то уж точно всех спасёт!
Много программистов = проще (и дешевле) найти человека на поддержку. Сейчас один автобус способен оставить ваше решение без поддержки на месяц-другой.
Если следовать этой логике, то:
Надо писать на PHP — потому что «программистов много».
Надо нанимать первого попавшегося — потому что «дешевле».
Надо молиться, чтобы «автобус» не приехал — потому что иначе проект развалится.
Но почему-то Bun.sh, Uber и TigerBeetle как-то рискнули и выбрали Zig — и, кажется, у них всё работает. Видимо, они предпочитают искать тех, кто действительно разбирается, а не просто «кого-нибудь из 90 тысяч».
Споры ни к чему не приводят. Потому что если инженер способен поддерживать только то, что «легаси 100 лет в обед», а не то, что технически оправдано — это уже вопрос не к языку, а к квалификации.
P.S. Мистический автобус, конечно, аргумент весомый. Но если система держится на одном человеке — проблема явно не в языке, а в подходе к разработке. Или вы считаете, что 90 тысяч C-разработчиков гарантированно защитят от любых форс-мажоров?
P.P.S. Кстати, если уж бояться «автобусов», то PHP-разработчики, судя по статистике, в зоне повышенного риска — их слишком много, вероятность ДТП выше. Может, тогда вообще запретим программистам выходить из дома? 😈
Надо писать на PHP — потому что «программистов много».
Вы это сами придумали, PHP не единственный популярный язык
Надо нанимать первого попавшегося — потому что «дешевле»
Вы это сами придумали, вам указали на то что в условиях выбора из большого числа кандидатов шанс найти подходящего укладывающегося в бюджет выше
Надо молиться, чтобы «автобус» не приехал — потому что иначе проект развалится
Вы это сами придумали, вам указали на то что в рамках малого числа кандидатов шанс того что вы останетесь с вундервафлей которую никто не может запустить после перезагрузки сервера выше
Но почему-то Bun.sh, Uber и TigerBeetle как-то рискнули и выбрали Zig — и, кажется, у них всё работает
В работоспособности Zig никто не сомневался, вы уверены что работаете в Uber или конторе сопоставимого размера? Возможности по найму специалистов сильно зависят от размера конторы.
О, внезапно появился эксперт по кадровому менеджменту! Давайте разберём ваши "аргументы"
Вы это сами придумали, PHP не единственный популярный язык
Вы правы - PHP не единственный популярный язык. Есть ещё COBOL! Там тоже много специалистов, и они точно не попадут под автобус - потому что уже на пенсии.
Вы это сами придумали, вам указали на то что в условиях выбора из большого числа кандидатов шанс найти подходящего укладывающегося в бюджет выше
Забавно, что вы считаете 90 тысяч резюме преимуществом. На практике это:
89 тысяч джунов, которые не знают, чем malloc отличается от calloc
999 мидлов, уверенных, что GC сделает всю работу за них
И если повезёт - 1 senior, который уже работает в FAANG
Вы это сами придумали, вам указали на то что в рамках малого числа кандидатов шанс того что вы останетесь с вундервафлей которую никто не может запустить после перезагрузки сервера выше
Если ваш код превращается в магический артефакт при смене разработчика - проблема не в языке, а в:
Архитектуре (точнее, её отсутствии)
Документации (которую вы, видимо, считаете буржуазным излишеством)
Процессах (о да, "у нас тут всё в голове у Васяна")
А если серьёзно: скомпилированный ocserv, с доработанной и отлаженной логикой, может работать годами и плевать ему на ребуты. Где спрашивается вундервафля?
В работоспособности Zig никто не сомневался, вы уверены что работаете в Uber или конторе сопоставимого размера? Возможности по найму специалистов сильно зависят от размера конторы.
Раз уж заговорили про размер компании:
Bun.sh создали 3 человека
TigerBeetle - и вовсе стартап. Но видимо, они просто не знали, что по вашей логике им "нельзя" использовать современные технологии
Ваш аргумент звучит как "нельзя использовать React, пока вы не стали Facebook"
По этой логике 99% стартапов должны писать на Visual Basic
P.S. Ваш подход прекрасно объясняет, почему 80% enterprise-кода - это поддерживаемый кошмар. Но продолжайте в том же духе - нам есть с чем сравнивать!
P.P.S. "Вы это сами придумали" — это не аргумент. Это отсутствие аргументов.
"Вы это сами придумали"
Вообще-то, это указание участнику дискуссии на то, что приведенный им довод не относится к теме дискуссии, либо, в лучшем случае, сам по себе не доказывает обсуждаемый тезис в целом.
Здесь есть, как минимум, два развития событий: тот, кому на это указывается, углубляет свою цепочку рассуждений, чтобы стало понятно и очевидно, каким образом «из А следует Б», либо оный участник рискует быть обвиненным в применении strawman argument.
О, внезапно проснулся профессор логики! Давайте разберём ваш удивительный вклад в дискуссию:
strawman argument
Забавно слышать это от человека, который:
Сам придумал тезис про «недоказанность связи»
Не заметил, что:
✓ Bun.sh/TigerBeetle уже доказали жизнеспособность Zig
✓ Наш проект РАБОТАЕТ и приносит прибыль
✓ Клиенты перестали уходить
Но да, конечно — это мы «не доказали тезис».
указание участнику дискуссии на то, что приведенный им довод не относится к теме дискуссии
Тема: «Выбор языка для стабильного решения»
Ваш вклад: «Вы неправильно используете логические конструкции»
Видимо, вы:
✓ Путаете Хабра с факультетом философии
✓ Считаете, что список fallacies важнее работающего кода
тот, кому на это указывается, углубляет свою цепочку рассуждений
Мы уже привели:
Конкретные примеры (Bun.sh, Uber)
Технические аргументы (память, производительность)
Бизнес-метрики (клиенты, серверы)
Ваш ответ: «Это не аргумент, потому что я так сказал»
P.S. Если для вас «логическая чистота» дискуссии важнее её содержания — может, вам действительно стоит писать учебники по риторике? А мы пока продолжим делать работающие системы. Как-то так.
P.P.S. На всякий случай напомню очевидное (но, видимо, не для всех):
Zig был выбран не потому что "модно", а потому что он:
Идеально подходит для модификации C-программ (наш случай)
Даёт контроль над памятью без головной боли (в отличие от ручного malloc/free)
Предоставляет современные фичи (компилятор, тестирование, кросс-платформенность)
Но да, конечно — я должен был:
✓ Остаться на PHP (где даже type safety — это фантастика)
✓ Или переписать всё на Java (где GC — это русская рулетка)
✓ Или нанять "любого из 90k C-разработчиков" (которые, как показывает практика, чаще пишут segfault'ы, чем работающий код)
Кажется, я сделал правильный выбор — даже если он не вписывается в вашу картину мира.
Может хватит отвечать с помощью иишки?
Bun это пока что проект "одного" человека, то что он рвет mode.js во-первых очень сильно притянуто за уши и там разница не в 3-10 раз а в 15-30% и то не во всех случаях, где то они равны а где -то выигрывает node.js.
На данный момент bun как и deno остаются нишевыми решениями и массового перехода на них не произошло и с учётом нового вектора развития nodejs ( SQLite, tests Runner, typescript ) этого явно не произойдет, по факту bun это своего рода io.js.
Zig возможно и был идеальным вариантом но из за этого они не получают такую поддержку комьюнити как например typescript-go а у них тоже был выбор между go и rust и объективно rust подходит лучше но по ряду причин они выбрали то что поможет получить максимальную поддержку комьюнити а не производительность и удобство.
никогда такого не было, сколько видел ничего хорошего "тысячи программистов" не делали) Двигают проект обычно единицы. Так что ТС абсолютно прав, а вам бы поучится у него.
Bun - хороший пример.
https://github.com/oven-sh/bun/issues
Гляньте с колько краш дефектов.
Когда у нас выбирали язык под высоконагруженный сервис, то остановились на Rust. Да медленнее не разработка, чем на Zig, но зато за три года в продакшне ни одного краша и общий показатель фичи/баги по компании самый низкий.
Bun - хороший пример.
https://github.com/oven-sh/bun/issues
Гляньте с колько краш дефектов.
Вы серьёзно приводите issues на GitHub как аргумент?
Тогда давайте посмотрим баги в Node.js (их в 10 раз больше)
Или в Spring Framework (там просто эпидемия)
Или, о ужас, в JVM (целые кладбища memory leak'ов)
то остановились на Rust. Да медленнее не разработка, чем на Zig, но зато за три года в продакшне ни одного краша и общий показатель фичи/баги по компании самый низкий
Поздравляю с удачным выбором! Только:
Мы модифицируем C-программу, а не пишем с нуля
Нам нужна была совместимость с существующим кодом
И, простите, но "три года без крашей" — это скорее заслуга инженеров, а не языка
то остановились на Rust
Самое смешное, что вы:
Хвалите Rust (молодой язык с малым пулом разработчиков)
Критикуете Zig (молодой язык с малым пулом разработчиков)
И при этом забываете, что ваш "идеальный" выбор — это ровно та же "проблема", за которую вы меня критикуете
Когда-нибудь и вы поймёте, что:
✓ Нет "серебряной пули"
✓ Выбор языка зависит от задачи
✓ А главный показатель — работающее решение, а не ваши личные предпочтения
P.S. Ваш Rust-сервис не крашится? Прекрасно! А теперь попробуйте найти 10 разработчиков, которые его поддержат быстрее, чем за месяц. Или это другое?
P.P.S. Кстати, раз уж заговорили про GitHub issues — может, поделитесь статистикой по вашему "идеальному" Rust-сервису? Или там "баги не считаются"?"
Вы серьёзно приводите issues на GitHub как аргумент?
Да. Что не так с тем, чтобы понимать какое количество не просто багов, а крашей у приложения которое должно крутить 24/7 твой софт?
Самое смешное
Я не хвалил и не критиковал Rust/Zig за их молодость. Вы это из своей головы взяли.
✓ А главный показатель — работающее решение, а не ваши личные предпочтения
Так и есть. Если приложение валяется в краше, то это отличный показатель работающего решения, правда?
Вы пишите на Zig и лучше меня знаете, что он имеет меньшую защиту от ошибок. А значит и разработчик на нем должен быть более опытный.
Но да. Если вы переходили с С кодовой базы, то у вас в команде соответственно и опыт имеется.
Отличный выбор!
Это камень не в огород автора, а бизнеса. Программист пишет на том, на чем хочет, но в рамках того, что позволяет бизнес. Если бизнес не хочет заморачиваться ("пофиг, на чём написано, лишь бы работало") - это проблемы бизнеса.
Программист пишет на том, на чем хочет, но в рамках того, что позволяет бизнес
Странно, в моей реальности хороший инженер:
Сначала изучает задачу
Потом выбирает инструмент под неё
И только потом пишет
Видимо, мы живём в разных вселенных. В вашей, похоже, код — это личное творческое самовыражение.
бизнес не хочет заморачиваться
А вот это уже ближе к истине! Только:
"Наш" бизнес «заморачивается» ровно настолько, чтобы клиенты не уходили
И странное совпадение — после перехода с PHP проблемы с уходящими клиентами исчезли
Может, это не бизнес «не заморачивается», а просто его критерии отличаются от ваших?
это проблемы бизнеса
Абсолютно верно! Поэтому:
Бизнес решил перестать краснеть перед клиентами
Бизнес выбрал стабильное решение
И, кажется, бизнес оказался прав — система теперь работает
P.S. Если в вашей картине мира нет места инженерам, которые «заморачиваются» за бизнес — это, конечно, печально. Но, возможно, вам просто не повезло с работодателями?
Бизнес выбрал стабильное решение
А бизнес точно в курсе деталей решения вашей проблемы?
По стране найдётся может человек 500, которые смогут это поддержать (или хотя бы понять код за день-другой). Попробуйте предложить бизнесу (например, такси в Воронеже) купить несколько Lamborghini - официального сервиса у нас нет, запчасти из-за рубежа через месяц. Не думаю, что бизнес согласится на такую авантюру.
По стране найдётся может человек 500, которые смогут это поддержать (или хотя бы понять код за день-другой).
Ваш аргумент:
«Мало специалистов → бизнес в опасности»
Реальность:
"Наш" бизнес уже просек разницу между:
«100 PHP-джунов, которые не могут починить утечку памяти»
«1 Zig-разработчик, который разбираются в системе»
Итог: клиенты перестали уходить, серверы не горят — странно, да?
Попробуйте предложить бизнесу (например, такси в Воронеже) купить несколько Lamborghini
Ваша аналогия настолько далека от реальности, что это уже поэзия:
Мы не покупали «гиперкар» — мы выбросили «Запорожец», который:
Глох на каждом светофоре (segfaults)
Требовал ремонта каждую неделю (memory leaks)
Разваливался на ходу (race conditions)
Теперь у нас нормальный автомобиль (не Lambo, а просто исправная Toyota)
А бизнес точно в курсе
Вы всерьёз считаете, что:
Клиенты перестали уходить → бизнес не заметил?
Серверы перестали падать → бизнес «не в курсе»?
Экономия на поддержке → бухгалтерия проигнорировала?
P.S. Если для вас «успешное решение» — это только то, где «500+ айтишников в каждом городе», тогда да — наш подход вам непонятен. Но, кажется, Stripe, Cloudflare и Uber как-то живут с этим. Может, и нам повезёт?
P.P.S. Кстати, если уж так переживаете за воронежское такси — может, сначала поинтересуетесь, сколько они тратят на ремонт своих Lada в год? А то ведь «официальный сервис есть» — но почему-то клиенты предпочитают Uber...
P.P.P.S. Самое забавное, что вы с таким умным видом рассуждаете о проекте, сути которого:
Даже не поняли (модифицированный ocserv — это не "вундервафля", а отлаженное enterprise-решение)
Не знаете критериев (стабильность > "много программистов")
Не видели в работе (годы работы без правок — это не баг, это фича)
Видимо, в вашей картине мира:
✓ Всё ПО должно постоянно ломаться, чтобы "специалисты" были нужны
✓ Отлаженные системы — это миф
✓ А главный KPI — количество резюме на HH, а не работающие решения
Но не переживайте — когда-нибудь и вы столкнётесь с проектами, где "просто работает" — это норма, а не фантастика. Возрастное. 😉
Ответьте, пожалуйста, на следующие вопросы: как быстро ваша компания сможет найти программиста для изменения бизнес-логики в вашем решении? Сколько будет стоить этот программист?
Может вам и кажется, что у вас Toyota, вот только запчасти к вашему авто будет найти несколько проблематичнее. Поиск запчастей - тоже проблема бизнеса.
О, наконец-то конкретные вопросы! Давайте разберём ваш новый шедевр экономического анализа:
как быстро ваша компания сможет найти программиста
Последняя правка бизнес-логики заняла 1 час рабочего времени (включая тесты). Выбор языка - это выбор между "сделать быстро" и "сделать и потом месяц фиксить".
Сколько будет стоить этот программист?
Ваша ошибка фундаментальна — вы считаете только зарплату, забывая про:
Стоимость простоя ("наши" серверы не падают)
Потерю клиентов (они больше не уходят)
Экономию на инфраструктуре (в 5 раз больше клиентов на 1 сервере)
P.S. «Дорогой» Zig-разработчик окупится за 2 месяца — за счёт снижения затрат на поддержку.
Может вам и кажется, что у вас Toyota, вот только запчасти к вашему авто будет найти несколько проблематичнее. Поиск запчастей - тоже проблема бизнеса.
Ваша аналогия разваливается при первом же взгляде:
Наш код не требует постоянных «запчастей» (работает годами)
«Ремонт» происходит в предсказуемое время (а не в 3 часа ночи)
«Механиков» мы готовим сами (внутренние знания > рыночная конъюнктура)
И вопрос на засыпку
Когда вы в последний раз видели enterprise-решение, где:
✓ Нет техдолга
✓ Ночные дежурства не нужны
✓ Клиенты не жалуются
P.P.S. Если для вас «идеальный проект» — это когда можно быстро нанять 100 «механиков» для вечного ремонта «Жигулей»... Может, проблема не в нашем выборе, а в ваших стандартах?
P.P.P.S. Кстати, о «запчастях» — сколько ваш бизнес тратит в год на «ремонт» вашего legacy-кода? Или это «не считается»?
Странно, конечно, в одной функции видеть и бизнес логику и аллокаторы. Чем старый добрый java/spring не зашёл?
В Java/Spring аллокаторы действительно спрятаны за сборщиком мусора и кучей абстракций — что отлично работает, пока вам не нужно понимать, куда девается память под нагрузкой. Stripe и Cloudflare как раз поэтому и переходят на Rust/Zig для критичных сервисов. Но если ваш критерий "странности" — отсутствие 10 слоёв DI, тогда да, мой код вам покажется подозрительным.
P.S. Кстати, в Java 21 уже добавили virtual threads — может, теперь наконец-то можно будет писать высоконагруженные сервисы без Spring Boot + 50 зависимостей? Шучу, конечно... Или нет?
В Java/Spring аллокаторы действительно спрятаны за сборщиком мусора и кучей абстракций — что отлично работает, пока вам не нужно понимать, куда девается память под нагрузкой. Stripe и Cloudflare как раз поэтому и переходят на Rust/Zig для критичных сервисов.
Можем попробовать прикинуть сколько памяти можно купить всего за одну месячную зарплату rust/go/zig разработчика
Но если ваш критерий "странности" — отсутствие 10 слоёв DI, тогда да, наш код вам покажется подозрительным.
Для меня DI это всего-навсего вынос оператора new из бизнес логики
Кстати, в Java 21 уже добавили virtual threads — может, теперь наконец-то можно будет писать высоконагруженные сервисы без Spring Boot + 50 зависимостей?
У вас точно high load?
Можем попробовать прикинуть сколько памяти можно купить всего за одну месячную зарплату rust/go/zig разработчика
Забавно, что вы считаете, будто проблема решается «покупкой памяти». Видимо, никогда не сталкивались с тем, как GC под нагрузкой превращается в русскую рулетку — когда приложение внезапно замирает на секунду, потому что JVM решила почистить бардак, который сама же и создала.
Но да, конечно — можно закидать железом любую архитектурную проблему. Только почему-то Stripe предпочёл потратить деньги не на сервера, а на переход с Java на Rust. Странные они, да?
Для меня DI это всего-навсего вынос оператора new из бизнес логики
Если для вас DI — это просто «вынести new», тогда Spring с его 15 слоями абстракции — это как стрелять из пушки по воробьям. В Zig зависимость инжектится ровно там, где нужна — без магии, без рефлексии, без тонны сгенерированного кода.
У вас точно high load?
У нас может и не было «хайлоада» в вашем понимании (миллионы RPS), зато есть:
предсказуемая работа без GC-лагов
код, который не разваливается от правки в соседнем модуле
P.S. Кстати, если уж говорить о деньгах — интересно, сколько стоит месяц простоя из-за того, что GC не справился с нагрузкой? Или час дебага «магического» поведения Spring-приложения? Но да, конечно, «память дешевле».
P.P.S. Кстати, если уж считать деньги — сколько вы тратите на поддержку всех этих Spring-зависимостей? Каждый security-апдейт ведь требует пересборки всего приложения. Или у вас production до сих пор на Java 8?
Забавно, что вы считаете, будто проблема решается «покупкой памяти». Видимо, никогда не сталкивались с тем, как GC под нагрузкой превращается в русскую рулетку — когда приложение внезапно замирает на секунду, потому что JVM решила почистить бардак, который сама же и создала.
Видимо вы не вкурсе насчет разных GC в современной Java, прежде чем пересказывать историю из нулевых актуализовали бы собственные знания.
Если для вас DI — это просто «вынести new», тогда Spring с его 15 слоями абстракции — это как стрелять из пушки по воробьям
Вы похоже просто не вкурсе Java-мира. Не то что бы знание java-мира обязательно, но рассуждать о том в чем не разбираетесь должно быть стыдно
P.S. Кстати, если уж говорить о деньгах — интересно, сколько стоит месяц простоя из-за того, что GC не справился с нагрузкой?
А Zig нагрузочного тестирования не требует? Или вам кажется что в мире Java нет такого?
Или час дебага «магического» поведения Spring-приложения?
Если для разработчика поведение его собственного инструмента "магическое", то это вопросы к конкретному разработчику, а не к инструменту.
О, внезапно проснулся гуру Java! Давайте разберём ваши жемчужины
Видимо вы не вкурсе насчет разных GC в современной Java, прежде чем пересказывать историю из нулевых актуализовали бы собственные знания.
Вы правы - в Java теперь целых 5 видов GC! И какой же из них:
Гарантирует отсутствие stop-the-world? (никакой)
Избавляет от memory leaks? (смешно)
Работает также предсказуемо, как ручное управление? (вы шутите)
P.S. ZGC - это круто, но он всё равно не волшебник. И да, я тестировал.
Вы похоже просто не вкурсе Java-мира. Не то что бы знание java-мира обязательно, но рассуждать о том в чем не разбираетесь должно быть стыдно
Забавно слышать от человека, который:
Лезит в чужую ветку с советами о бизнесе, о котором ничего не знает
Считает, что DI в Spring сводится к «вынесу-ка я new»
Путает «магию» фреймворка с плохой документацией
А Zig нагрузочного тестирования не требует? Или вам кажется что в мире Java нет такого?
Ах да, конечно:
В Zig тесты показывают, где я накосячил
В Java тесты показывают, где JVM решила устроить фестиваль сборки мусора
И вопрос на засыпку
Когда вы в последний раз:
Объясняли клиенту, почему его запрос обрабатывался 5 секунд (потому что GC)
Дебажили OOM в продакшене из-за неочевидного retain в лямбде
Пересобирали весь кластер из-за security-дыры в Spring-зависимости?
P.S. Если для вас «не знать Spring» = «не разбираться в разработке» — поздравляю, вы идеальный кандидат на позицию «корпоратного программиста года». Только вот Uber почему-то таких не ищет... Странно, да?
Гарантирует отсутствие stop-the-world? (никакой)
Epsilon GC. Какой вопрос такой ответ.
Объясняли клиенту, почему его запрос обрабатывался 5 секунд (потому что GC)
Пока что сценарии нагрузочного тестирования отвечают ПРОМ-нагрузке подобное не требуется. Вцелом у вас почему-то во всем GC виноват, хотя, например, плохая работа с конкурентными ресурсами убьет производительность в любом языке.
Дебажили OOM в продакшене из-за неочевидного retain в лямбде
Никогда - в ПРОД запрещен дебаг службой безопасности.
Пересобирали весь кластер из-за security-дыры в Spring-зависимости?
У вас странная фиксация на необходимости пересборки при обновлении зависимостей, обновлять зависимости приходилось не раз, но если мы говорим про Spring то это никогда не было задачей даже на день - свежие версии выходят, о изменениях настроек по-умолчанию и api известно сильно заранее.
А к Zig новые версии не выходят? Или в имеющихся каким-то образом гарантируется отсутствие ошибок в генерируемой компилятором коде?
В Zig тесты показывают, где я накосячил
Zig пишут люди, они могут ошибаться - их ошибки также могут проявляться во время нагрузочного тестирования.
В Java тесты показывают, где JVM решила устроить фестиваль сборки мусора
Ошибки разработчика также могут быть видны во время нагрузочного тестирования
Если для вас «не знать Spring» = «не разбираться в разработке» — поздравляю, вы идеальный кандидат на позицию «корпоратного программиста года»
Показатель для меня не знать инструменты и пытаться судить о них.
Из нулевых? Истории вроде перехода с Cassandra на ScyllaDB из-за GC (зависание ноды до 4-5 секунд на топовом железе во время сборки мусора) от Discord еще достаточно свежие. GC при всем его развитии не перестает быть GC, со всеми его вытекающими минусами.
Будет спрос на Zig - будет и предложение (программисты).
Для начала надо иметь нагрузку как дискорд/cf/azure и прочие случае перехода на раст. Когда люди, у которых 100 юзеров и 10 запросов в минуту начинают рассуждать о том, как их будет затрагивать работа GC это просто не серьёзно.
это просто не серьёзно
Вы совершенно правы — рассуждать о чужом бизнесе, не зная деталей, действительно несерьёзно.
А что если наши 100 пользователей — это:
VPN-инфраструктура для банковских отделений
Где каждый сеанс обрабатывает финансовые транзакции
С требованиями SLA 99.99%
Уже не так однозначно, верно?
Ничего из перечисленного само по себе не говорит ни о каком high load и тем более о не возможности использовать язык с GC. В deutsche bank сервис на джаве обрабатывал эвен сорс всех дневных трейдов мировых бирж по бондам и деривативам, с требование не более 3 микросекунд на операцию и прекрасно с этим справлялся.
В deutsche bank сервис на джаве обрабатывал эвен сорс всех дневных трейдов мировых бирж
Я там свечку держал. Знали бы вы какой кровью это было достигнуто и как было больно программистам вы бы не приводили это в пример.
Но было то. Дима Труб даже доклад про это делал на CEE-SECR 2012.
А в чем конкретно боль программистов была? Было бы интересно почитать)
Это давно было, если сейчас правильно тезисно вспомню то:
GC был отключен, вообще
все нужные объекты выделялись заблаговременно через Object Pool паттерн
соответственно запрещено использовать любые сторонние библиотеки
работа со строками была сделана тоже через боль и страдания (т.к. родные immutable, а GC вырублен)
подключены несколько C либ чтобы работать с общими системными буферами (сеть и файлы)
Для начала надо иметь нагрузку как дискорд/cf/azure и прочие случае перехода на раст.
Наличие такой нагрузки тоже не говорит о необходимости перехода на раст (хотя я против него ничего не имею).
Истории вроде перехода с Cassandra на ScyllaDB из-за GC (зависание ноды до 4-5 секунд на топовом железе во время сборки мусора) от Discord еще достаточно свежие.
Сцилла и Кассандра две совершенно разных базы, гц далеко не ведущую роль играет в их результатах. Дискорд не осилил его затюнить под свои нужды, ну есть примеры компаний которые осилили)
Как раз Scylla разрабатывалась чуть ли не дроп ин заменой Cassandra, она же не просто так поддерживает CQL (Cassandra Query Language). В пять раз быстрее по бенчам (ну и как авторы говорят, что на одну и туже нагрузку нужно в десять раз меньше нод)
Есть примеры компаний, которые осилили затюнить Cassandra под их нагрузки... Мне интересны конкретные примеры. Обычно такой тюнинг заканчивается компромиссами. Стоит ли оно того и надолго ли это?
Как раз Scylla разрабатывалась чуть ли не дроп ин заменой Cassandra, она же не просто так поддерживает CQL (Cassandra Query Language).
Тут нет никаких противоречий с тем что я написал)
В пять раз быстрее по бенчам (ну и как авторы говорят, что на одну и туже нагрузку нужно в десять раз меньше нод)
В определенных сценариях да, но как я и сказал, гц в этом играет далеко не ведущую роль. Если вкратце - SEDA просто плохой выбор для хайлоада и очень сильно уступает thread per core. Если в точности воспроизвести сциллу на джаве, плюсовый вариант всё ещё будет быстрее, но не в разы.
Есть примеры компаний, которые осилили затюнить Cassandra под их нагрузки... Мне интересны конкретные примеры.
Заходите в бложик одноклассников на хабре и наслаждайтесь) Кассандра у них основная база, используемая за редкими исключениями практически для всего
надолго ли это?
15 лет полет нормальный
может, теперь наконец-то можно будет писать высоконагруженные сервисы без Spring Boot + 50 зависимостей
Люди пишут высоконагруженные сервисы на Java десятилетиями без спринг бута и виртуальных тредов)
Классика. Бюджет ограничен, но вместо того чтобы попытаться привести в порядок код на PHP, переписываем все на два других языка, экономя аж целых 45 MB памяти)
Ах, ну да, конечно — 45 МБ в простое это же "мелочь"!
Давайте лучше посмотрим, что происходит при 1к+ клиентов:
PHP:
Каждый новый коннект — это новый процесс с копией всего на свете
1000 клиентов? 1000 копий тех же самых библиотек в памяти
А теперь добавьте сюда утечки из-за циклических ссылок и глобальных переменных
Итог: сервер начинает свопиться, клиенты отваливаются, админ бегает с перезагрузками
Zig:
Один процесс, контролируемые аллокации, общие ресурсы
Никаких неожиданных утечек — потому что память не "магическая", а явная
Итог: сервер улыбается и жуёт трафик, клиенты довольны
Так что "гирлянда" была именно на PHP — только это не новогоднее украшение, а лампочки серверного стойла, мигающие от перегрузки.
И главный вопрос
Когда вы в последний раз сами:
Объясняли клиенту, почему его данные потерялись из-за magic_quotes_gpc?
Дебажили race condition в PHP-сессиях?
Перезапускали продакшен в 3 ночи, потому что скрипт сжёг всю память?
P.S. 45 МБ - это просто приятный бонус. Настоящая экономия в том, что теперь мы не теряем клиентов и не тратим ночи на поддержку.
Если для вас "экономия памяти" — это смешно, значит, вы либо никогда не масштабировали PHP-сервисы, либо успешно перекладывали эту боль на админов. В любом случае — поздравляю с удачным избеганием реальных проблем.
P.P.S. А PHP-код я привёл в порядок, но только он остался исключительно там где ему место — рисует HTML.
не могу ничего сказать про Zig, но PHP код даже на беглый взгляд выглядит ... нехорошо. Скоере всего, это писал какой-то джун задёшево. Да ещё автор упоминает про magic_quotes_gpc - это же жуткая древность и моветон.
Да ещё автор упоминает про magic_quotes_gpc - это же жуткая древность и моветон.
Да, это была гипербола (спасибо, что заметили). Но если вас смущает только это — поздравляю: значит, остальные проблемы кода настолько очевидны, что даже спорить не о чем.
Скоере всего, это писал какой-то джун задёшево
А вот это уже интересно. Вы:
Не знаете контекста (кто, когда и зачем это писал)
Не видели весь код (только фрагменты)
Но уже уверенно ставите диагноз
Видимо, у вас есть дар — определять квалификацию разработчика по «беглому взгляду». Может, откроете курсы?
не могу ничего сказать про Zig
Это единственное разумное в вашем комментарии. И да — теперь у нас:
Нет магических преобразований типов
Нет неожиданных утечек памяти
И главное — нет «беглых взглядов» от посторонних экспертов
P.S. Если вам так интересно — могу прислать пару примеров «нехорошего» кода на PHP. Для ностальгии. Или для осознания прогресса.
P.P.S. Кстати, если уж говорить про «древность» — как думаете, через сколько лет ваш текущий стек тоже будут так же вспоминать? 😏
Что ты вы очень остро реагируете на вполне безобидные комментарии
безобидные комментарии
Напомню, что оригинальный комментарий:
С ходу поставил диагноз квалификации разработчика
Проигнорировал технические аргументы
Свёл обсуждение к субъективным впечатлениям
Но да, конечно — это я «остро реагирую», а не кто-то пришёл ляпнуть глупость и обижается на ответ.
Он вроде бы не обижается на ответ, да даже и не ответил вам никак. А по поводу квалификации, в статье есть пример PHP кода, по нему можно понять уровень разработчика который его писал.
Вы правда слишком остро реагируете думая что на вас все накинудись, но это не так, это просто обсуждение
Видимо, у вас есть дар — определять квалификацию разработчика по «беглому взгляду».
Это не "дар" а профессиональная квалификация. Приведённый в статье код на РНР кошмарен, ни один сколько-нибудь профессиональный разработчик такого себе не позволит. Начиная буквально с первой строки с die
, дальше можно уже не смотреть. Впрочем, повсеместное использование суперглобалов тоже доставляет.
Это Вы писали? С чего такая обида на совершенно справедливое замечание @Mausglov? В любом случае, рассуждать о недостатках какого-либо языка на примере такого кода абсолютно бессмысленно – там проблема не в языке, а в программисте.
Подскажите пожалуйста, чем был обусловлен выбор именно в пользу Zig а не к примеру Rust?
Такой же вопрос. Добавлю сюда Go.
И вопрос ко всем: почему, если php и всякие Питоны настолько хуже (насколько говорит автор), чем например Zig, на них (на php и Питоне) пишут так много всяких бэков для веба, включая совсем новые проекты? И пишут даже, не побоюсь этих слов, на Java и C#.
И вопрос к автору: почему раньше был отдельный процесс на каждое vpn-соединение, а теперь один процесс для всех? Нельзя ли было так же сделать, не меняя язык бэка?
На мой взгляд, Zig — это современный аналог С. Вопрос о том, почему для веб-сервисов выбирают PHP, Python или Go, а не С думаю сразу даст понимание). Отсутствие нужных библиотек тоже дает причину пока не брать его в серьезный проект.
Ок, но тогда почему не Rust? Всё же он распространен гораздо шире.
Вопрос о том, почему для веб-сервисов выбирают PHP, Python или Go, а не С думаю сразу даст понимание).
Но мой вопрос был совсем другой, вот жеж)
Zig это нечто промежуточное между C и Rust. Zig имеет множество крутых фич как в Rust (tagged unions, optionals, явные ошибки), но при этом имеет более свободную модель выделения памяти как в C (аллокаторы и defer очень удобны, но всё же полностью не защищают от утечек/двойного освобождения).
Спасибо за интерес к деталям нашего выбора! Позвольте пояснить мой подход более развернуто:
1. О выборе языков в принципе
В профессиональной разработке существует 4 основных пути выбора языка:
✓ Личные предпочтения технического руководства
✓ Корпоративные стандарты и комплаенс
✓ Популярные заблуждения ("все пишут на X")
✓ Осознанный выбор под конкретные требования
Я выбрал последний путь.
2. О распределении языков в нашем проекте
Zig: для низкоуровневой части (модификация C-программы)
Идеальная совместимость с C ABI
Контроль памяти без сложностей Rust
Минимальные накладные расходы
Go: для вспомогательных сервисов
Удобен для concurrent-задач
GC не критичен для логирования
Быстрая разработка
PHP: основной бэкенд
Только немного подрпавил, так как удовлетворяет требованиям
3. О философии выбора
Я принципиально не утверждаю, что:
✓ PHP/Python "хуже"
✓ Zig/Rust "лучше"
Каждый язык имеет свою нишу:
Когда нужен контроль памяти — берем Zig/Rust
Когда важна скорость разработки — Go/Python
Когда работает legacy — не ломаем без нужды
Каждый случай выбора языка под проект заслуживает отдельного анализа. В моём сценарии:
✓ Модификация C-кода → Zig
✓ Высокоуровневые сервисы → Go
✓ Основной бэкенд → PHP
почему раньше был отдельный процесс на каждое vpn-соединение, а теперь один процесс для всех?
Вероятно моя формулировка в статье создала неверное понимание происходящего. Давайте разберём архитектурные изменения подробней.
1. Как было раньше:
На каждое подключение создавался отдельный процесс PHP
В каждом процессе загружалась вся кодовая база скриптов
Плюс работал основной процесс ocserv-worker
→ Двойная нагрузка на систему
2. Как сейчас:
Вся бизнес-логика встроена непосредственно в процедуру авторизации
Никаких дополнительных процессов не создаётся
Модифицированный ocserv-worker обрабатывает всё сам
P.S. Если бы я разрабатывал систему с нуля сегодня — возможно, выбрал бы другие инструменты. Но профессиональный подход — это работать с текущими реалиями, а не гнаться за мейнстримом
Спасибо за первый по-настоящему конструктивный вопрос! Действительно, и Zig, и Rust могут ломать обратную совместимость, но в нашем случае выбор Zig был обусловлен несколькими ключевыми факторами:
Частота изменений vs критичность
Да, Zig ещё молод и действительно меняется чаще Rust
Но: наши изменения в бизнес-логике происходят раз в 5-10 лет
Обновление Zig-части (если потребуется) займёт ~1 день работы
Сложность миграции
В Rust breaking changes часто затрагивают систему владения
В Zig изменения обычно касаются:
API компилятора (не нашего кода)
Второстепенных фич (async/await и т.п.)
Конкретный наш случай
Мы зафиксировали версию Zig (0.14)
Код максимально простой (нет сложных абстракций)
Даже если ABI Zig сломается — пересборка займёт минуты
Практический компромисс
Rust даёт больше гарантий, но:
Требует больше времени на разработку
Сложнее интегрируется с нашим legacy C-кодом
Zig выбрали как "золотую середину" между:
Контролем памяти (как в Rust)
Простотой C
P.S. Для высоконагруженных новых проектов я бы склонился к Rust. Но для нашей задачи (минимальная модификация стабильного C-кода) Zig оказался идеальным инструментом — даже с учётом его молодости.
P.P.S. Плюсую в карму за вопрос по делу :)
У меня вопрос к пачке memset: что за магические константы используются? В смысле, конечно, они, очевидно, используют размерность, определяемую структурами в Zig. Но тогда не лучше ли генерировать заголовочный файл с этими константами из Zig при компиляции, чтобы, например, не забыть при внесении изменений в основной код?
О, внезапно появился эксперт по кадровому менеджменту! Давайте разберём ваши "аргументы"
О, внезапно проснулся гуру Java! Давайте разберём ваши жемчужины
будто нейронка ответы в комментах пишет, или как минимум помогает) либо это шаблонность мышления, что ещё печальнее. в любом случае странная реакция - нарекать тех, кто что-то вам возразил, гуру и экспертами
Сейчас многие начали свои сообщения прогонять чрез LLM, например в Яндекс браузер он встроен.
ладно там вычитка подготавливаемого материала(сомнительно, но окей), здесь комментарии уже, то есть прямая коммуникация. когда человек начинает коммуницировать, и тем более "острить" с помощью LLM - это реально выглядит как дорога в один конец. особенно если человек немолод, потому что навыки утрачиваются с двойной скоростью, и их необходимо поддерживать самостоятельно
А может меня вообще нету? Есть только AI-агент, почему нет. Пол хабра сейчас заваленно вайб-кодингом и тем как сделать своего агента.
Автор явно намучился со старой версией и явно тащится от новой, поэтому реагирует остро на любую критику)
будто нейронка ответы в комментах пишет
Не могу понять я пишу настолько хорошо или настолько плохо.Как вы относситесь к нейронкам? Чтобы я понимал, меня сейчас оскорбили или похвалили.
что ещё печальнее
Самое прекрасное - это ваша уверенность, что понимаете чужой мыслительный процесс, на основании пары комментариев.
в любом случае странная реакция - нарекать тех, кто что-то вам возразил, гуру и экспертами
А возражать ради возражения это не странно в наше время, совершенно с вами согласен. Или предлагать всё переписать на Java, там где JVM не было и в помине.
Спасибо за интересный способ. Я тоже экспериментировал с созданием расширения для PHP на Zig и убедился, что это возможно. Однако я бы не стал использовать язык версии до стабильной, так как высок риск нарушения обратной совместимости. В Zig это происходит почти постоянно, как и на Rust до стабильной версии.
Вероятно, я бы рассмотрел изменение архитектуры и процессов, например, с использованием других PHP-фреймворков (roadrunner, reactphp, amphp, swoole) или создание отдельного микросервиса на Go. Но это повлияет на продолжительность и стоимость внедрения. Возможно, ваш подход окажется самым экономичным и быстрым, но имеет высокий риск для дальнейшей эксплуатации из-за возможных проблем.
какой агрессивный автор
Меня всегда интересовало, как устроено человеческое мышление и взаимодействие, поэтому психология и коммуникация стали естественной областью для размышлений.
Учитывая что в профиле автора указано это )
"Если вы придёте ко мне с сжатыми кулаками, я могу вам гарантировать, что мои кулаки сожмутся ещё крепче. Но если вы придёте ко мне и скажете: "Давайте обсудим наши разногласия", — мы обнаружим, что расстояние между нами не так велико."
— Дейл Карнеги
Как заметил Дейл Карнеги: "Когда в дискуссию входят со сжатыми кулаками, трудно ожидать рукопожатия".
Мы могли бы продуктивно обсудить:
Реальные технические компромиссы между Zig и другими языками
Конкретные метрики поддержки кода
Экономику разработки
Но когда диалог начинается с диагнозов "это писал джун" и предположений о некомпетентности бизнеса, или предложения переписать всё на Java — увы, это сразу задаёт неконструктивный тон.
У вас опечатка в первом же предложении.
Привет, Хабр! Я bi-cycle разработчик.
Я так понимаю это из тех, кто в инстаграмах себя называет синьором, потому что он сам так решил.
Я много лет слушаю стереотип, как несправедливо агрессивны к людям Rust разработчики:) Но я ни разу там такого в общении не встречал ужаса. Моя конспирологическая теория — именно отсутствие GC делает комментарии человека злыми.
PS Действительно отвечает как нейросеть.
Вот это я понимаю job safety development. После переноса кода на zig работодатель просто не сможет адекватно заменить автора другим разработчиком. И автор сможет ставить любые условия по дальнейшей работе. Учитесь, котятки (sarcasm)
Замечательная статья, блистательные комментарии, непревзойдённый Zig. Но я так и не смог понять, как связаны между собой VPN и баннеры и почему, вообще, они так неверояно критически важны?
:-D
OCVPN — это серверная часть VPN, она раздаёт доступ для аккаунтов. В штатном ocvpn есть такая функция: при подключении показать сообщение (появится в всплывающем окне) — это называется баннер. Штатная версия позволяет задать 1 статичный баннер через файл конфигурации сервера, ocserv.conf — этого не достаточно.
В данном проекте баннеры используются как способ доставки важной информации к пользователю: срок окончания подписки, какие-то сведения, etc.
Я как фанат Rust на самом деле поддерживаю в вашем случае переход именно на Zig. Во многом пожалуй в как раз контексте поддержке кода (за что вас тут в комментариях пытаются критиковать). Тут я поддержу выбор Zig:
1) В эпоху LLM поддерживать код на Rust всё еще сложно, потому что нужно хорошо владеть приемами "борьбы с лайфтаймами" и в них придется погрузиться, чтобы хоть что-то поменять в проекте, когда это понадобится. То есть взять не раст-инженера и "побыстрому" посадить его на проект не получится.
А вот Zig в этом плане простой как веник. За пару дней можно выучить весь синтаксис языка, а дальше ну это по сути Си, только не Си. Я 100% уверен, что с минимальной помощью LLM на проект можно нанять PHPшера Perl-иста, и он разберется.
2) Учитывая, что это билинг (как-то приходилось писать билинг), тут критична даже не столько скорость (хотя и она важна), как предсказуемость времени выполнения участков кода. И вот GC языки тут сильно мешают. Помню в Python по такой причине приходилось выключать GC и использовать только ref counter. По-сути получали странную версию Rust (это было до 2015 года релиза раста).
Выбор по-сути между C C++ Rust Zig. Из этой четверки опять же Rust требует дополнительных знаний, а Zig отличается просто эргономикой и синтаксисом от Си (если очень грубо). Опять имхо Zig выглядит выгодно.
Помню в Python по такой причине приходилось выключать GC и использовать только ref counter. По-сути получали странную версию Rust (это было до 2015 года релиза раста).
Интересный опыт :]
Я как фанат Rust на самом деле поддерживаю в вашем случае переход именно на Zig. Во многом пожалуй в как раз контексте поддержке кода (за что вас тут в комментариях пытаются критиковать). Тут я поддержу выбор Zig:
1) В эпоху LLM поддерживать код на Rust всё еще сложно, потому что нужно хорошо владеть приемами "борьбы с лайфтаймами" и в них придется погрузиться, чтобы хоть что-то поменять в проекте, когда это понадобится. То есть взять не раст-инженера и "побыстрому" посадить его на проект не получится.
А вот Zig в этом плане простой как веник. За пару дней можно выучить весь синтаксис языка, а дальше ну это по сути Си, только не Си. Я 100% уверен, что с минимальной помощью LLM на проект можно нанять PHPшера Perl-иста, и он разберется.
Огромное спасибо за ваш взвешенный комментарий! Приятно встретить человека, который понимает суть инженерных компромиссов. Вы правы в каждом пункте:
Ваша мысль про LLM и Rust — бьёт в точку, хотя изначально не планировал на этом акцентироваться. Zig действительно даёт:
✓ Предсказуемую кривую обучения
✓ Прозрачную интеграцию с C
✓ Минимальный cognitive overhead для новых разработчиков
P.S. Ваш комментарий — редкий пример того, как должно выглядеть профессиональное обсуждение технологий. Без холиваров, с пониманием реальных инженерных задач. Но вы рискуете быть заминусованым за непопулярное мнение :)
P.P.S. И да — вы точно описали мой опыт: имея базовые навыки в C, в Zig разобрался за пару часов. Первые шаги с Rust заняли недели. Но Rust я тоже люблю
Судя по комментариям, автор из тех, кто решил использовать технологию по приколу. Ну, то есть, захотелось изучить и применить что-то новое сразу "в бою". Остается пожелать удачи новоприбывшим разбираться в новом коде. Потому что, как показывает опыт, переписывание с одного на другое едва ли делает проект лучше и поддержку проще.
Как только появляется новый язык, так сразу "о Госпади, все старые языки плохие, вот новый всех переплюнул". Грамотный код и подход способны сделать проект быстрым на любом языке. В тысячный раз, у всех языков свои плюсы и минусы. Почти любой язык будет быстрым, если писать с умом. Он будет понятным и гибким, если следовать паттернам, солид и использовать передовые фреймворки. Если всё лежит и везде баги - проблема явно не в выборе языка.
Судя по всему автор просто вышел из мира старого монолита.
Коллеги, не трогайте бедную PHP, её не любят, потому что 10-20 лет назад на ней много сделали тяп-ляп. Про паттерны, инкапсуляцию раньше мало кто думал. Это не значит, что на ней нельзя сделать круто, продумав всё
походу нейросеть и статью написала и в каментах отвечает
Чел не осилил пхп :(
От PHP к Zig: как я избавился от костылей в биллинг-системе