Преимущества LINQ над функциональными цепочками методов

Обсуждался Котлин Слак о возможности добавления деревьев кода для поддержки таких вещей, как C # LINQ.

В C # LINQ есть много приложений, но я хочу сосредоточиться только на одном (потому что другие уже предположительно покрыты синтаксисом Kotlin): составление SQL-запросов к удаленным базам данных.

Предпосылки:

Вопрос : что деревья выражений добавляют к синтаксису, который так важен для этой задачи? Насколько хорош SQL-конструктор без них?

Насколько хорош запрос dsl может быть без деревьев выражений?

Как показал JINQ , вы можете получить очень далеко, проанализировав байт-код, чтобы понять намерение разработчика и, таким образом, перевести предикат SQL. Таким образом, в принципе, деревья выражений не являются существенными для построения великолепно выглядящего запроса dsl:

val alices = database.customerStream().where { it.name == "Alice" } 

Даже без хакерства, такого как анализ байт-кода, можно получить достойный запрос dsl с генерацией кода. Querydsl и JOOQ – отличные примеры. С небольшим количеством кода обмотки Котлина вы можете написать

 val alices = db.findAll(QCustomer.customer, { it.name.eq("Alice") }) 

Как деревья выражений помогают строить запрос dsl

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

 val alices = database.customerStream().where { it.name == "Alice" } 

Аргумент функции where будет expression которое мы можем проверить во время выполнения и перевести его на SQL или на другой язык запросов. Поскольку деревья выражений представляют собой код, вам не нужно переключаться между парадигмой Kotlin и SQL для написания запросов. Код запроса, выраженный с помощью linq / jinq, выглядит почти таким же, независимо от того, выполняются ли они в памяти с использованием POCO / POJO или в движке базы данных с использованием языка запросов. Компилятор также может выполнять большую проверку типов. Кроме того, очень легко заменить базовую базу данных в представлении памяти, чтобы ускорить выполнение тестов.

Дальнейшее чтение:

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

JOOQ и Querydsl:

Типичным решением ORM было использование DSL или встроенного DSL из логики приложения. Хотя с этими схемами были достигнуты большие успехи, достигнув высшей точки в JOOQ и Querydsl, в этой системе все еще есть много предостережений:

  • многие парадигмы, к которым люди, пишущие эти запросы, используют (а именно тип безопасности), либо отсутствуют, либо различны по ключевым причинам
  • точная семантика неочевидна: в предыдущем ответе предлагается использовать метод расширения eq для выполнения db-родного фильтра равенства. Очень вероятно, что новый разработчик ошибочно будет использовать equals вместо eq .
  • эта вторая точка усугубляется сложностью тестирования: использование живого соединителя с поддельными данными является довольно сложной проблемой, поэтому в зависимости от процедуры тестирования неправильный код jooqDB.where { it.name.equals("alice") } может не обнаруживается до тех пор, пока не будет значительно ниже по конвейеру разработки.

Jinq

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

Хотя я еще не использовал Jinq, я полагаю, что еще одна причина, по которой Jinq не видит широко распространенного принятия, во многом потому, что он пытается использовать гораздо более жесткий домен для решения проблемы: построение запросов из AST намного проще, чем построение запросов из байт код по той же причине, что создание контура компилятора проще, чем создание transcompiler. Хотя я не могу не посоветовать свою шляпу команде Jinq за такую ​​потрясающую работу, я также не могу не думать, что им мешают их инструменты: сложно построить запросы из байт-кода. По определению java-байт-код предназначен для работы на JVM, пытаясь модифицировать это обязательство для другого переводчика – очень трудная проблема.

Моя текущая работа не позволяет мне использовать традиционную базу данных, но если бы я должен был переключать проекты, зная, что мне понадобится большое количество данных в моем DAL, я, скорее всего, отступлю от Kotlin и Java обратно в .net, в основном из-за Linq, а не исследовать Jinq. «Линк из Котлина» вполне может измениться.

Поддержка от поставщиков БД:

Соединения базы данных LINQ to SQL и LINQ-to-mongo широко распространены в сообществе .net. Это связано с тем, что они являются первыми партиями, имеют высокое качество и действуют достаточно просто: компиляция AST для SQL (или языка манго-запроса), по крайней мере, концептуально прямолинейна. Многие традиционные требования ORM применяются, но поставщики (Microsoft и Mongo) продолжают решать эти проблемы.

Если бы Kotlin поддерживал деревья кода времени исполнения в аналогичном ключе Linq, и если Kotlin продолжает набирать обороты по текущему курсу, то я считаю, что команды MongoDB и Hibernate быстро начнут модернизировать существующие LINQ-to-X разъемы для поддержки Клиенты Kotlin, и в конечном итоге даже более медленные компании, такие как Microsoft и IBM, начнут поддерживать тот же поток.

Линк из Котлин

Более того, интересны точные роли, которые уникальные концепции Котлина «типа приемника» и агрессивная реализация inline могут играть в пространстве Linq. Linq-from-Kotlin может быть более эффективным, чем LINQ-from-C #.

где C #

 someInterface .where(customer -> customer.Name.StartsWith("A") && ComplexFunctionCallDoneByMongoDriver(customer)) .select(customer -> new ResultObject(customer.Name, customer.Age, OtherContext())) 

Котлин мог бы добиться успехов:

 someInterface .filter { it.name startsWith "A" && inlinedComplexFunctionCallDoneOnDB(it) } //inlined methods would have their AST exposed -> can be run on the DB process instead of on the driver. .map { ResultObject(name, age, otherContext()) } //uses a reciever type, no need to specify "customer ->" //otherContext() might also be inlined 

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

Другие виды использования:

Стоит отметить, что предположение о применении времени исполнения кода AST не соответствует действительности:

другие [области выполнения AST-доменов] [уже] предположительно покрыты синтаксисом Kotlin

Причина, по которой я это поднял, в первую очередь заключалась в том, что я был недоволен нулевой защитой Kotlin и ее взаимодействием с Mockito . Проведя некоторое время, исследуя проблему, для Kotlin нет рамок Mocking, только java-рамки, которые могут быть из Котлина, с некоторой болью.

Некоторые нерешенные проблемы как в java-домене, так и в домене Kotlin:

  • Издевательские рамки, как указано выше. Имея доступ к AST, все умные, но причудливые трюки вокруг аргумент-операции-заказа, используемые Мокито, устарели. Другие более традиционные издевательские фреймворки приобретают гораздо более интуитивный и безопасный тип интерфейса.
  • выражения привязки, для интерфейсов пользовательского интерфейса или иначе, часто передаются в строки. Рассмотрим структуру пользовательского интерфейса, где разработчики могут писать notifyOfUIElementChange { this.model.displayName } вместо notifyOfUIElementChange("model.displayName") . Последний страдает от калечащей проблемы устаревания, если кто-то переименовывает свойство.
    • Я очень рад видеть, что могут сделать ребята ControlsFX или Томас Микула с такой функцией.
  • похоже на специфический для Kotlin Linq: Я подозреваю, что приложения Kotlin здесь могут обеспечить ряд инструментов, о которых я не знаю. Но я очень уверен, что они существуют.

Мне очень нравится Линк, и я не могу не думать, что с сосредоточением внимания Коттина на проблемах промышленности модуль Linq-from-Kotlin будет идеально подходит и сделает несколько человеческих жизней, в том числе и моих, намного проще.