Re[13]: Какая мотивация делать проекты на Ruby?
От: Ziaw Россия  
Дата: 10.12.18 08:55
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Теоретически, современные движки RDBMS позволяют спроектировать приложение как набор view c instead of триггерами, которые и будут реализовывать нужную нам бизнес-логику.

S>Тогда клиент сможет работать с ним исключительно в терминах CRUD-операций, и фреймворки, заточенные на публикацию ER-модели в виде REST или GUI, будут уместны.
S>На практике эта идея упирается в ограничения на исполняемый в рамках СУБД код. Поэтому, как правило, в СУБД лежат достаточно тупые таблицы с минимумом триггеров, а ограничения целостности вводятся не для обеспечения бизнес-логики, а для семантических оптимизаций.

Я не сторонник так делать. Конечно REST модель не должна полностью ложиться на таблицы, но она на них опирается в подавляющем большинстве сценариев. То есть если у нас есть /orders/:id, то почти наверняка есть соответствующая таблица с ключом.

S>REST-интерфейс выставляет наружу некоторую специальную информационную модель. Она достаточно нетривиальным образом ложится на модель данных.

S>Обычно в разговорах об архитектуре под CRUD понимают достаточно узкую штуку: это набор методов по манипуляции именно данными в таблицах.
S>То есть Update здесь — это просто Update, сохраняем атрибуты одной Entity. В Rest update — это PUT или PATCH; за ними мы ожидаем увидеть какую-то бизнес-логику.

В RoR эта логика может выглядеть примерно так (этот DSL не из RoR, это state_machine для RoR):
  event(:cancel) { transition from: :enlisted, to: :placed, unless: :external? }

  before_transition on: :cancel do |application, _transition|
    application.processed_at = nil
    application.order_id = nil
  end


Код, обрабатывающий PUT /application/:id/cancel

def cancel
  @application.cancel unless @application.placed?
end


S>REST, который выставляется между клиентом и сервером, может быть устроен существенно по-другому, чем GUI. И, естественно, существенно по-другому, чем внутреннее устройство таблиц БД.


Так и я говорю, что UI к REST привязан слабо. И чем слабее, тем лучше. А вот зачем RESTу существенно отличаться от основных сущностей системы — мне непонятно. Или почему, мы не можем основные сущности хранить в таблицах.

S>Вот теперь на первый план выезжают фреймворки, которые помогают мне строить серверную часть вот таких вот приложений.

S>Не нравится мобильный клиент альфа-банка — ок, давайте посмотрим на какой-нибудь booking.com или momondo. Там главное "окно" — это выхлоп "поискового запроса". Нет никакой таблицы в БД, которая бы соответстовала view "подходящие варианты размещения". Там есть несколько таблиц, и нетривиальная логика по извлечению из них данных.

Это не норма, а крайний случай. Результаты поиска чего-то, отчеты, анализ данных не ложится на таблицы. Остальное-то ложится. Само бронирование наверняка лежит в каком-то хранилище по определенному ключу и мы работаем с ним как с одной сущностью.

Что с того, что есть сущности без таблиц? Мне кажется, что ты намекаешь, что мы получаем здесь проблему в рельсах, но не могу понять какую.

S>Но в том, что он плохой, виноват точно не тот фреймворк, который они взяли.


Вот-вот. И я не могу понять, зачем мы вообще начали говорить про плохие интерфейсы.

S>Прошу прощения, если мой тон вас обижает. Я всего лишь пытаюсь убедиться в соответствии терминологии, чтобы обсуждение было конструктивным.


Дело не в обиде, дело в том, что так мы диалога не построим.

S>Отлично. Вот мне хочется понять — каким образом идеология RoR помогает лучше, чем идеология C#/Linq.


В RoR получается писать меньше кода, он понятнее и читабельнее. В нем меньше технологического клея.

S>Не, я не отстаиваю. Я хочу разобраться в том, где я заблуждаюсь.


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

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

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

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

S>Всё, что я услышал в качестве критики статики — "необходимость создавать и поддерживать бесчисленные DTO". Ну, так это справедливо только в том случае, если DTO нужно декларировать заранее и явно.

S>Современная статика копает в сторону автоматического вывода типов DTO вместо явного их описания.
S>То есть там, где в динамике мы в результате Select FirstName, LastName, DateDiff(Now(), BirthDate, Year) as Age получаем просто рекордсет, из которого надо доставать данные по именам, в статике мы получаем экземпляр анонимного типа со вполне определёнными типами FirstName, LastName, и Age. Что потенциально позволяет нам сразу же отлавливать несоответствия использования.

Да, я краем глаза слежу за этим процессом. Но за последние 5 лет он так и не оформился в какой-то готовый к использованию инструмент. База отдельно, HTTP отдельно, формы отдельно. И несмотря на все успехи автоматического вывода типов, немалая часть кода занята перекладыванием данных.

S>Ок, вернёмся к теме. Каким образом нам рельсы помогают проверить корректность данных, приехавших в PUT?


Смотря что делает этот PUT и что нужно проверить. И я думаю, неверно рассуждать о том, что они как-то помогают. Они дают возможность писать простой код проверки, это помощь?

S>Выбор глагола подталкивает к решению. Когда мы реализуем PUT, то у нас уже есть resource id; и нам нетрудно реализовать if (newObject.Equals(existingObject)) return 200 Ok, чтобы пропустить весь блок бизнес-логики, связанный с изменением состояния (типа отправки письма "заказ принят" и прочих штук). Когда мы реализуем Post, то надо прямо отдельно думать о том, "а что если это не новая операция, а повторная отправка старой, которая потерялась".

S>А что, одного этого мало? Даже тупой веб-клиент, который отправляет PUT, получит корректный результат при повторном нажатии на кнопку.

Пусть будет PUT, я не против. Саму идемпотентность все равно придется реализовывать в логике операции.

S>Можно и закруглиться. Я ожидал совета, какие книги мне почитать. Ну, или примеров про то, как RoR помогает. Вы приводите косвенные признаки — ваше приложение на рельсах проще, чем оно было бы на .Net.

S>Было бы интересно посмотреть на фрагмент RoR кода, который плохо перепишется на C#. Потому что без этого всё упирается в opinion и вкусовщину.

Я не могу приводить какие-то серьезные фрагменты реального кода. Книги по RoR? Их наверное масса, я изучал по туториалам, официальной доке и читая код фреймворка.

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

http://railscasts.com/episodes/416-form-objects

Видео более 5 лет, некоторые вещи ушли вперед, но сам подход, как иллюстрация одного из способов решения может быть интересен. Я бы делал несколько не так, но для иллюстрации подойдет.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.