RubyRussia 2019. Никита Шильников об алгебраическиех эффектах

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

    image

    Расскажи, чем ты занимаешься и как это связано с Ruby?

    Я работаю в двух компаниях, проекты которых написаны на Ruby. В одной мы делаем биллинг, можно сказать, что это такой полу-энтерпрайз, а в другой создаем SaaS-сервис. Так сложилось, что много занимаюсь open source. Четыре года назад я заинтересовался одним проектом, нашел недостатки функциональности в нем, решили исправить и пошло-поехало. Сейчас я core-разработчик двух организаций и комьюнити. Все можно увидеть на моем Github. Одна часть работы касается баз данных rom-rb, а другая dry-rb – это набор библиотек на разные случаи жизни.

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

    Здесь нужно небольшое овервью. Экосистема dry-rb вдохновлена функциональным программированием. Но при ее разработке кое-что не давало покоя. К примеру, ты разрабатываешь SaaS-сервис и есть простая задача по изоляции данных. Вроде все понятно, имеется какой-то сервис, в нем регистрируются компании, и у них должен отсутствовать доступ к данным друг друга. Решить можно разными способами. Но с чисто функциональной точки зрения я не находил ответ на то, как это сделать, кроме как явной передачи аргументов по всему коду. Придумал свое «нефункциональное» решение и с ним жил.

    В конце 2018 года в React появились hooks. Когда в первый раз увидел их API, я подумал, что нельзя такие вещи сделать так просто. Прекрасно представляю, как работает JavaScript и решил, что здесь явно не все чисто, используются глобальные переменные или что-то еще. В моем представлении о том, как работает программа, это было либо невозможно, либо использовался какой-то грязный хак. Решил изучить вопрос.

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

    Ты меня прямо заинтриговал с React hooks. Думал там что-то очень простое типа call stack, замыкания, текущий scope.

    Оно на самом деле так и есть. Проблема в том, что у тебя имеется какая-то статья, которая описывает семантику и то, как с научной точки зрения это должно работать. Если следуешь спецификации, то у тебя появляется возможно сделать библиотеку. В случае React это тоже библиотека или, скажем, фреймворк, который предоставляет какой-то API. Если им пользоваться правильно, то все прекрасно работает. Но если ты пойдешь влево или вправо, то это может плохо кончиться. В React они просто запретили использовать hooks в условиях. Им пришлось так сделать. Это одно из ограничений.

    Это как-то связано с математическим доказательством корректности кода?

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

    А как ты относишься к типам и статически типизированным языкам программирования?

    Очень положительно. Например, у нас бэкэнд на Ruby, а фронтэнд на такой вещи как ReasonML. Это OCaml, но с другим синтаксисом. При прочих равных делаю выбор в сторону этой системы типов. Она довольно простая и существует целый ряд языков, в которых подобная или похожая реализация. Чем больше типов, тем лучше. Вместе с тем, я пишу бэкенд на Ruby и меня все устраивает. Я являюсь разработчиком тех инструментов, с которыми работаю и они всегда были про типы: dry-types, dry-struct, dry-schema, dry-validation, dry-monads. Они про то, чтобы описывать типы, которые приходят из базы данных, от пользователя, от внешних систем. Чтобы ты всегда знал, с чем у тебя работает код Ruby. Пускай даже он сам не типизирован, но ты точно можешь быть уверен в типе переменной, с которой ты работаешь.

    Есть слухи, что в Ruby 3 будут типы. Что ты об этом скажешь?

    У меня есть опыт работы с Python. Когда туда завезли типы, то тулинг был не очень развит и меня не впечатлило. Сейчас там ситуация лучше. Туда можно заходить и описывать все типами и применять какой-то тулинг, который будет проверять, что твоя программа корректна. Речь про какую-то замену компилятора, про то, что у нас сейчас делает sorbet. У Python это заняло несколько лет. Я всегда приветствую движение в сторону типов, но не питаю никаких иллюзий.

    Смотрел на новый синтаксис, который планируется реализовать с точки зрения кода Ruby?

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

    Что тебе еще хотелось бы видеть в Ruby, как видишь его развитие?

    Мне была бы интересна кооперативная многозадачность. У нас уже есть кооперативная многозадачность в виде fiber. Нам все равно не хватает возможности запускать их на нескольких тредах. Есть варианты того, как это будет сделано и до конца непонятно в каком виде. Учитывая, что у Ruby, у C реализации есть довольно солидное наследие, то Матц не хочет ломать обратную совместимость. Я склоняюсь к комбинации файберов и нескольких одновременно запущенных потоков. Может быть, что-то вроде Guild будет работать.

    В этом году на конференцию приезжает Yukihiro Matsumoto, автор Ruby. Что тебе было бы интересно с ним обсудить за чашкой кофе или бокалом саке на афтепати?

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

    Увидимся на RubyRussia!

    Напомним, что конференция уже в эту субботу, регистрация еще открыта.

    Будут не только доклады, но и стенды лучших компаний:

    Организатор — Evrone
    Генеральный партнер — Toptal
    Золотой партнер — Gett
    Серебряные партнеры — Валарм, JetBrains, Bookmate и Cashwagon
    Бронзовый партнер — InSales
    RubyRussia
    0,00
    Конференция разработчиков на Ruby и RoR
    Поделиться публикацией

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

      +1
      Тема си Так и не понял, что такое алгебраические эффекты.
      Думаю, простой пример кода мог бы помочь (лучше с пояснениями)
        0
        немного погуглил раз (пример на пальцах и js) и два (более абстрактно, но после первого — понятно о чем там речь) и

        три
        Отрывок
        A simple example of a handler is:
        handler {read(; k) 7→ k “Bob”}
        which provides a constant input string “Bob” each time read is called. We can, of
        course, generalise it to a function that takes a string s and returns a handler that
        feeds it to read:
        alwaysRead def = fun s 7→ handler {read(; k) 7→ k s}
        This handler works as follows: whenever read is called, we ignore its unit parameter
        and capture its continuation in a function k that expects the resulting string and
        resumes the evaluation when applied. Next, instead of calling read, we evaluate
        the computation in the handling clause: we resume the continuation k, but instead
        of reading the string from interactive input, we yield the constant string s. The
        handler implicitly continues to handle the continuation, so any read in the handled
        computation again yields s. If the handled computation calls any operation other
        than read, the call escapes the handler, but the handler again wraps itself around the
        continuation so that it may handle any further read calls. For example, evaluating
        with (alwaysRead “Bob”) handle printFullName
        first prints out “What is your name?” as print is unhandled. Then, read is handled
        so “Bob” gets bound to forename. Similarly, the second print is unhandled, and
        in the second read, “Bob” gets bound to surname as well and finally “Bob Bob” is
        printed out.

        — т.е. если кто знает что такое Dependency Injection и как работает async / await / yield в джаваскрипте (или других языках) — то несложно понять аналогию работы: в контексте вызовов у вас целевая функция может быть подменена, а при выходе за контекст вызова — ее поведение вернется обратно, вот и все.

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

      Самое читаемое