Pull to refresh

Comments 56

Эта статья будет не полной без самого популярного комментария из обсуждения на Reddit:


Let me sum up.
"We're JS twinks with no real experience with backend software dev, so instead of learning a new language that's well proven on the backend like Ruby or Python, we picked a JavaScript tool with almost no track record as a backend platform. Then we realized it sucks for a huge number of backend applications! So naturally…
1) we picked yet another completely unproven, alpha quality platform… 2) that nobody else uses in production, so support is hard to come by when it breaks,… 3) with a custom syntax (even though we picked node instead of a good platform specifically to avoid learning a new syntax)… 4) AND WE REWROTE ALL OUR SHIT BECAUSE YOLO"
Whoever makes tech decisions for this team is an irresponsible, incompetent idiot who has no business being near production systems.

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

так всегда начинается :-) у меня один продакшн-сервис для работы с кредитными картами написан на Crystal, но он однозначно недоступен снаружи :)

Присоединяюсь.


Crystal отличается высокой производительностью. Для моих задач он оказался в 2 раза быстрее Node.

Да что угодно компилируемое быстрее ноды :-)


Он использует очень мало памяти. Crystal обычно надо менее чем 5 Мб на процесс, а Node — более 200 Мб.

Ну это как приложение напишешь.


У него имеется отличная стандартная библиотека, в результате для решения типичной задачи нам понадобилось лишь 12 зависимостей, в сравнении с сотней зависимостей Node.

На D возможно хватило бы и одной — vibe.d


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

В D аналогично, более того..


До сих пор нет настоящего параллелизма (в Node его тоже нет).

В D он мало того, что есть, так ещё некоторым контролем времени компиляции. Файберы могут баланситься на воркеры. Есть и реализация каналов как в го.


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

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


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

D тоже их выводит, но более строго. Например, не пихает алгебраические типы где ни попадя, как ниже в комментах.


Всё ещё нет поддержки Windows (меня это не беспокоит, работаю я на Mac, код разворачиваю на Linux).

А меня беспокоит, ибо работаю под виндой. И D работает и под линуксом и под виндой. И тоже умеет компилироваться через LLVM.


Нет инкрементной компиляции (это было бы очень удобно, так как сейчас, для компиляции нашей системы после внесения изменений в код, требуется около 8 секунд).

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


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

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

Для D есть аналог Passport.js? Пока удалось найти только https://github.com/thaven/oauth, но хотелось бы стабильную версию, больше готовых провайдеров и хоть какую-то активность в репозитории.

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

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

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

Зачем переходить именно на Ruby Cristal, если есть много других более развитых платформ бэкэнда. Те же рельсы или Go.
И чем вам Node не нравится
Фактически на одном языке и фронтэнд и бэкэнд
Написали же, именно это авторам оказалось не нужно.
Эти цепочки промисов тяжело тестировать, отлаживать, код получается не особенно вразумительным. Часто бывает так, что просто глядя на код тяжело понять даже то, в каком порядке выполняются задачи и подзадачи.


async/await через babel еще 2 года назад уже отлично работали
UFO just landed and posted this here

мне Crystal нравится (потому что я рубист), но вся проблема в том, что язык еще не релизнулся: могут быть баги, обратно-несовместимые изменения и прочие прелести

гарантированно будут (я надеюсь).

А если взять какую-то ruby библиотеку и тупо компильнуть кристалом — взлетит? Или там такой игривый руби-лайк синтаксис, сейчас я руби, а сейчас нет? (я не рубист, если что)

в 98% случаях не взлетит, потребует хотя бы рихтовки напильником.


Crystal просто основан на некоторых идеях из Ruby.


Но вообще это статически-типизируемый язык с type unions, редкая штука.


То есть тип Int32 — не может быть nilable, а Int32 | Nil может (другая запись — Int32?).


И это очень сильно и удобно (и да, можно Int64 | String, например, но вообще типы он сам выведет при компиляции, если явно не писать).

Int64 | String — это же обычные дженерики, нет?

Нет, метод может вернуть type union Int64 | String.


При этом по факту у вас есть две автоматически созданные ветви исполнения по типу возвращаемого результата.


def iors : Int64 | String
  Math.rand > 0.5 ? 5 : "s"
end

r = iors
if r.is_a?(String)
  puts "wow #{r}"
end

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

более корректно код писать как:


def iors
  Random.rand > 0.5 ? 5 : "s"
end

r = iors
if r.is_a?(String)
  puts "wow #{r}"
end
Наверное тут имеются в виду алгебраические типы данных. То есть, например, метод может вернуть или int32 или string, а потом в зависимости от того, что по факту вернулось (с помощью if или какого pattern matching) будет своя ветка исполнения.
Ещё один пример — функция возщает или ответ или ошибку

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


def iors : Int64 | (puts "Welcome to hell" > Nil ? String : Nil)
    Math.rand > 0.5 ? 5 : "s"
end
Несложно заметить, что структура этих двух примеров очень похожа. Однако, когда отпала необходимость в промисах, общий объем кода уменьшился. При написании более крупных приложений это заметно ещё сильнее. Серверный код DuoCMS 5 состоит из примерно 15609 строк на JavaScript. Объём кода DuoCMS 6 близок к 10186 строкам. На данный момент DuoCMS 6 имеет больше возможностей, для реализации которых потребовалось на 30% меньше кода. При этом, благодаря отсутствию промисов, этот код гораздо легче читать и поддерживать.


Можно и порефакторить этот js и получим тоже — читаемый код и уменьшение кодовой базы
const router  = require('express').Router();

app.get('/', (req, res) => res.send('Hello World!'));

app.post('/api/users', async (req, res) => {
  const {body} = request;
  if (!body) {
    return res.send("no user provided")
  }
  
  await UserService.save(request.body);
  res.send('user saved');
})
К тому же на crystal нет обработки ошибки сохранения пользователя — замечательное сравнение.

Скорее всего, обработка исключений происходит внутри фреймворка (как в sinatra), так что всё ок

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

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

Ну на деле Kemal, — это просто первая ласточка, сейчас есть и иные каркасы, типа https://ambercr.io


Во-вторых, да, async/await — прекрасная концепция.


А в остальном, — Crystal надежнее и удобнее в силу своей статической типизации, тут его ближайший конкурент все-таки — tsnode Golang.

Я — активный фанат кристала и мне больно смотреть, как в него приходят js'еры и рубисты и начинают буквально ср*ть в опенсорс, ни разу не используя преимущества языка. Они думают, что они всё ещё в динамическом ЯП.


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


А ещё автор забыл упомянуть макросы. Метапрограммирование есть и в кристале, и это одна из самых главных его особенностей.

А почему тогда не nim? Явно быстрее crystal, есть то же самое метапрограммирование через макросы и прочее.
К тому же там как раз планируется большое кол-во изменений в отношении к GC — деструкторы, которым не нужен GC (в компилятор добавился новый проход «destroyer», в котором в код будут вставляться вызовы деструкторов в нужных местах), к тому же строки и последовательности станут свободными от GC (уже есть эксперименты с этим).
В IRC/Gitter можете пообщаться на эту тему с Araq (создателем языка).
Меня вымораживает отсутствие неймспейсов (из-за универсального способа вызова методов) — в интеллисенсе миллион функций может быть при импорте из нескольких внешних библиотек. Тут даже go-lang поприятнее как-то, но в нем нет исключений. :(
Можно сделать импорты как в питоне:
from sequtils import nil
echo sequtils.repeat('h', 15)

Не миллион, не преувеличивайте, они же фильтруются по типу первого аргумента.

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

Макросы на строках, без гигиены, в негомоиконном языке — это не метапрограммирование, это курам на смех.

Ну как раз в Crystal макросы — на AST.


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

> Ну как раз в Crystal макросы — на AST.

В презентации сказано, что АСТ — только промежуточное представление и в итоге из него генерятся строки.

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

И толку, если там в середине были строки? Нормальную макросистему на этом изобразить нельзя, в строках просто нету требуемой информации.

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


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


class UserController {
  requests(router) { // router уже держит /api 
    router.post('/users', this.handleRequest(this.addUser))
  }

  addUser(req) {
    // вообще у нас прикручен валидатор на запросы, но ладно уж
    if (!req.body) throw new ServerError("no user provided"); // addUser исполняется в промисе, так что ошибка вывалится в catch

    return UserService.save(req.body)
        .then(() => 'user saved');
  }
}
Они, как правило, либо были медленнее, чем Node, либо не так удобны для целей разработки.

Интересно, python медленее nodejs (если все-таки использовать асинхронность) или менее удобен?)


А так crystal наконец-то похож на язык, который как python по гибкости, только компилируется. Надо будет глянуть.

пока желательно только для инфраструктуры внутренней.


наружу раньше февраля не стоит.

Жесткого плана нет (есть карта).


Ранее была амбициозная цель к 2018 году создать Crystal 1.0, готовый к промышленной эксплуатации.


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


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

UFO just landed and posted this here
Я как рубист на кристал давно засматриваюсь. Попробовать очень хочу, но пока никак.
Потому что Nim очень сырой и в нем хаотично надерганы концепции из кучи других языков.
Julia все же больше для математиков и ученых создана.
Nim уже не очень сырой, багов всё меньше, и все фичи в языке смотрятся с друг другом нормально (например дженерики с концептами)
называйте меня как хотите, но сравнивать языки со скобками и языки с «end» это…

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


5.times { |i| puts i }

yo = -> { puts "yo" }
yo.call
ужас — кроме фигурных скобок в строке могут быть только некоторые другие специальные символы, иначе теряеться вся суть.
yo = -> { puts "yo" } 


зачем это? проще уже без сколбок

увы, ужас непонят. все читаемо.

Sign up to leave a comment.