Здравствуйте, Ziaw, Вы писали:
Z>Давай закругляться. В теме уже нет конструктива, все что я услышал, про RoR в этом посте — у тебя большой скепитизим в том, что RoR подходит для бэкенда Яндекс.Такси. В этом я даже с тобой готов согласиться, когда сущностей немного, процессы известны и стоит задача сделать надежное как космический корабль и такое же быстрое серверное приложение, рельсы не лучший выбор. Хотя опять же есть нюансы, есть примеры крупных торговых площадок даже на PHP. Значит можно и даже чем-то для них оправдано.
Здравствуйте, Ziaw, Вы писали: Z>Суть у них одна.
Верно, "суть" одна. К сожалению, одной только "сути" недостаточно. Теоретически, современные движки RDBMS позволяют спроектировать приложение как набор view c instead of триггерами, которые и будут реализовывать нужную нам бизнес-логику.
Тогда клиент сможет работать с ним исключительно в терминах CRUD-операций, и фреймворки, заточенные на публикацию ER-модели в виде REST или GUI, будут уместны.
На практике эта идея упирается в ограничения на исполняемый в рамках СУБД код. Поэтому, как правило, в СУБД лежат достаточно тупые таблицы с минимумом триггеров, а ограничения целостности вводятся не для обеспечения бизнес-логики, а для семантических оптимизаций.
REST-интерфейс выставляет наружу некоторую специальную информационную модель. Она достаточно нетривиальным образом ложится на модель данных.
Обычно в разговорах об архитектуре под CRUD понимают достаточно узкую штуку: это набор методов по манипуляции именно данными в таблицах.
То есть Update здесь — это просто Update, сохраняем атрибуты одной Entity. В Rest update — это PUT или PATCH; за ними мы ожидаем увидеть какую-то бизнес-логику. Z>Откуда взялся мобильный клиент в теме про веб-фреймворки? Я говорил, что мне не нравится в веб-клиенте бизнеса, который, похоже, делался по принципу — засунем все в одно SPA.
Эмм, из обсуждения того, как устроены удобные для пользователя приложения.
Ещё раз поясню: мобильные приложения как раз демонстрируют современные достижения юзабилити.
Во-первых, потому что там нет адского легаси в стиле "отцы терпели — и ты потерпишь", а во-вторых, потому что мобильник сам по себе очень неудобен. И "традиционные" подходы на нём сосут. Достаточно попробовать открыть этот сайт на айфоне, чтобы получить наглядный пример.
То есть когда мы пишем мобильное приложение, то мы вынужденно думаем не о том, как "выставить в гуе" список заказов, список адресов, список кредитных карточек, и что там ещё у нас может быть списком, а о том, какие действия выполняет пользователь. И пляшем от них. В хорошем десктопном приложении надо делать так же. Но примеров таких приложений — гораздо меньше, чем мобильных.
REST, который выставляется между клиентом и сервером, может быть устроен существенно по-другому, чем GUI. И, естественно, существенно по-другому, чем внутреннее устройство таблиц БД.
Вот теперь на первый план выезжают фреймворки, которые помогают мне строить серверную часть вот таких вот приложений.
Не нравится мобильный клиент альфа-банка — ок, давайте посмотрим на какой-нибудь booking.com или momondo. Там главное "окно" — это выхлоп "поискового запроса". Нет никакой таблицы в БД, которая бы соответстовала view "подходящие варианты размещения". Там есть несколько таблиц, и нетривиальная логика по извлечению из них данных.
Z>Нет, я пытаюсь понять, почему "нормальные" интерфейсы не дают мне делать то, что мне нужно.
Вы просто взяли пример "плохого" интерфейса Я же не говорю, что он хороший — он плохой.
Но в том, что он плохой, виноват точно не тот фреймворк, который они взяли.
S>>Эмм, вы вообще master-detail видели? Ну, чтобы убедиться, что мы об одном и том же говорим?
Z>Я устал уже от отсылок к delphi, mobile, тонкостей толкования REST. Давай вернемся к теме и разберемся, чем конкретно хороша и плоха динамика в веб-разработке.
Отлично, давайте. Z>Не надо мне в каждом посте "тонко" намекать, что твое толкование REST, нормального интерфейса или master-detail чем-то лучше моего. Если что-то считаешь лучшим решением, приведи его, объясни его плюсы, будь готов ответить на вопросы, а все эти намеки свысока "вы вообще master-detail видели" задолбали.
Прошу прощения, если мой тон вас обижает. Я всего лишь пытаюсь убедиться в соответствии терминологии, чтобы обсуждение было конструктивным.
Z>Понятно. Очень спорно, но не по теме. По теме это укладывается в REST и сценарий PATCH заказа. И вполне нормально вписывается в идеологию RoR.
Отлично. Вот мне хочется понять — каким образом идеология RoR помогает лучше, чем идеология C#/Linq.
Z>Возможно тебе хотели показать, насколько проще делаются банальные сценарии, потому, что показать что-то сложное за пять минут нельзя. А ты составил поверхностное суждение и теперь его отстаиваешь.
Не, я не отстаиваю. Я хочу разобраться в том, где я заблуждаюсь.
Z>Например, разве, делфи оказалась плоха, потому, что можно было бросить грид на форму? Между прочим это был прекрасный инструмент, который был вытеснен C# и .net, как языком так и платформой. Я сам в свое время перешел с радостью, надоело вручную управлять памятью и писать на паскале. Сам редактор форм там был ничуть хуже winforms, а во чем-то даже лучше.
Я тоже в своё время очень много написал на Delphi. Просто
Z>Точно так же я и на RoR ушел. Надоело вручную управлять парком велосипедов. Возможно есть приложения и бизнесы, в которых содержание этого парка оправдано, но мне не нравится аргументация в стиле: "отстутствие необходимости писать велосипед на каждый чих провоцирует нас не писать их совсем, это расслабляет и делает наши приложения неудобными для пользователей". Нужен велосипед — пишем. Преимущество RoR в том, что многое можно брать в готовом виде и кастомизировать ровно то, что нужно.
S>> Ничего странного в REST с "искусственными ключами" нету. И наличие привязки к ER не означает эквивалентность ER. Эта привязка может быть выполнена большим количеством разнообразных способов.
Z>Так в чем тогда проблема?
В том, что большая часть кода приложения — это преобразования данных из одной структуры в другую. В динамике это сводится к перекладыванию из одной хешмапы в другую. В статике — это преобразования типов.
И теоретически как раз статический контроль типов позволяет нам оперативно отслеживать некорректности этих преобразований. Я пока не могу понять, чем же динамика лучше.
Всё, что я услышал в качестве критики статики — "необходимость создавать и поддерживать бесчисленные DTO". Ну, так это справедливо только в том случае, если DTO нужно декларировать заранее и явно. Современная статика копает в сторону автоматического вывода типов DTO вместо явного их описания.
То есть там, где в динамике мы в результате Select FirstName, LastName, DateDiff(Now(), BirthDate, Year) as Age получаем просто рекордсет, из которого надо доставать данные по именам, в статике мы получаем экземпляр анонимного типа со вполне определёнными типами FirstName, LastName, и Age. Что потенциально позволяет нам сразу же отлавливать несоответствия использования. Z>Пусть будет PUT, мы опять ушли от темы. Где идемпотентно — PUT, где нет — POST. Если простое изменение данных, в сущность, если это операция — то в операцию. Как это относится к рельсам или .net?
Ок, вернёмся к теме. Каким образом нам рельсы помогают проверить корректность данных, приехавших в PUT?
Z>Насколько я понимаю, в этом плане все равно придется что-то изобретать для идемпотентности, хоть POST это будет, хоть PUT, задача программиста сделать идемпотентный обработчик не решается выбором глагола.
Выбор глагола подталкивает к решению. Когда мы реализуем PUT, то у нас уже есть resource id; и нам нетрудно реализовать if (newObject.Equals(existingObject)) return 200 Ok, чтобы пропустить весь блок бизнес-логики, связанный с изменением состояния (типа отправки письма "заказ принят" и прочих штук). Когда мы реализуем Post, то надо прямо отдельно думать о том, "а что если это не новая операция, а повторная отправка старой, которая потерялась".
S>>Ну, мне важнее всего код клиента. Потому что сервер — он один, а клиентов — много. С клиента реализовать корректную смену статуса через patch проще, чем через POST и прочее. Мне не надо прикапывать RequestID и прочее — вполне себе тупой клиент способен поддержать смену статуса, не приводя к ошибкам.
Z>Чем проще-то? Не могу понять. Ну кроме того, что не надо дополнительно документировать идемпотентность.
А что, одного этого мало? Даже тупой веб-клиент, который отправляет PUT, получит корректный результат при повторном нажатии на кнопку.
Z>Все остальное — тонкости понимания REST, предпочтения в UI, что там было в Delphi, идут параллельно теме и тоже совсем не конструктивно. Ты занял позицию гуру — кругом говно, читайте книги, там все рассказано. Я не просил совета, какие книги мне читать.
Можно и закруглиться. Я ожидал совета, какие книги мне почитать. Ну, или примеров про то, как RoR помогает. Вы приводите косвенные признаки — ваше приложение на рельсах проще, чем оно было бы на .Net.
Было бы интересно посмотреть на фрагмент RoR кода, который плохо перепишется на C#. Потому что без этого всё упирается в opinion и вкусовщину.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, msorc, Вы писали:
M>В Gett RoR/Ruby используется.
Почему бы и нет. Я бы тоже может использовал. То, что RoR это не лучший выбор исходя из чисто технологических вопросов, не означает, что это не может быть лучшим выборам по каким-то другим критериям. Я же говорю, даже на PHP создают серьезные решения, при выборе платформы учитывается множество факторов. В первую очередь предпочтения CTO. А уж доведет CTO продукт до ума или нет — заранее никогда не скажешь, там столько факторов.
Здравствуйте, 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? Их наверное масса, я изучал по туториалам, официальной доке и читая код фреймворка.
Можешь посмотреть вот этот эпизод, мне кажется он близок к одной из тем, вокруг которых мы ходим.
Видео более 5 лет, некоторые вещи ушли вперед, но сам подход, как иллюстрация одного из способов решения может быть интересен. Я бы делал несколько не так, но для иллюстрации подойдет.
Здравствуйте, Ziaw, Вы писали: Z>Я не сторонник так делать. Конечно REST модель не должна полностью ложиться на таблицы, но она на них опирается в подавляющем большинстве сценариев. То есть если у нас есть /orders/:id, то почти наверняка есть соответствующая таблица с ключом.
Угу. Плюс архивная таблица, в которой лежат старые заказы. То есть, на самом деле, это три разных таблицы, потому что есть заказы разных типов — на услугу, на товар, на товар в электронной форме.
Атрибуты и жизненный цикл у этих заказов — разные, но мы выставляем их через единую навигацию для упрощения тех клиентов, которым неважны подробности типа.
Z>В RoR эта логика может выглядеть примерно так (этот DSL не из RoR, это state_machine для RoR): Z>
Z> event(:cancel) { transition from: :enlisted, to: :placed, unless: :external? }
Z> before_transition on: :cancel do |application, _transition|
Z> application.processed_at = nil
Z> application.order_id = nil
Z> end
Z>
Z>Код, обрабатывающий PUT /application/:id/cancel
Z>
Круто. А кто проверяет, что в application.processed_at нет опечатки — ну там, что мы случайно не заменили в одном месте его на .handled_at?
Z>Так и я говорю, что UI к REST привязан слабо. И чем слабее, тем лучше. А вот зачем RESTу существенно отличаться от основных сущностей системы — мне непонятно. Или почему, мы не можем основные сущности хранить в таблицах.
Можем. Но мы храним не сами эти сущности. К примеру, сущность "адрес" вполне может лежать в таблице, но самостоятельного URL у неё нету — она публикуется только как часть более крупного документа.
Или, к примеру, у нас события в календаре лежат в таблице в виде (begin, end, description), а наружу мы выдаём документы типа "расписание на день", где есть как слоты, занятые событиями, так и пустые.
Сущность "слот" вообще не лежит ни в какой таблице.
Z>Это не норма, а крайний случай. Результаты поиска чего-то, отчеты, анализ данных не ложится на таблицы. Остальное-то ложится. Само бронирование наверняка лежит в каком-то хранилище по определенному ключу и мы работаем с ним как с одной сущностью.
Мы работаем с ним как с "одной сущностью" только в рамках внешнего API нашего сервера приложений.
Как оно внутри там устроено — х.з. Очень, очень вряд ли там какая-то одна реляционая таблица — скорее всего, "бронирование" — это конгломерат записей из нескольких таблиц (root object, гости, история оплат, история переписки, ещё дофига чего). Может, там какой-то NoSQL, может, SQL, может, то и другое сразу. Наверняка есть какая-то интеграция с бэк-ендами гостиничных сетей (очень сомневаюсь, что клерки в Mariott вручную переносят данные из панельки booking.com в свою внутреннюю систему бронирования вручную). Вся эта кунсткамера выставлена наружу как обманчиво простой "ресурс".
Z>Что с того, что есть сущности без таблиц? Мне кажется, что ты намекаешь, что мы получаем здесь проблему в рельсах, но не могу понять какую.
Я намекаю на то, что весь современный миддл-тир сводится к перекладыванию данных из одного источника в другой. И 90% ошибок — это ошибки, допущенные при согласовании вот этих протоколов.
Идея статики — в том, что мы ловим такие ошибки статически. Что делается для этого в динамике? Ну, кроме интеграционных тестов?
Z>Ну вот при разработке на RoR всего этого нет. Этот праздник к нам приходит только в интеграциях со сторонними системами. Если приложение состоит целиком из интеграций, возможно выигрыша от RoR мы и не получим.
Ну так даже безо всяких сторонних систем, приложение — это интеграция "GUI" c "SQL", отношения между которыми достаточно произвольные.
Да, офигенно круто, что нам не надо декларировать DTO — мы просто берём то, что нам вернул слой доступа к данным, и скармливаем в GUI, который выводит это дело в HTML.
Но это же ровно то, что мы имели в любых доисторических фреймворках вроде ASP (без Net): просто биндинг по именам, recordset.GetValue('Name') и погнали. Z>Да, я краем глаза слежу за этим процессом. Но за последние 5 лет он так и не оформился в какой-то готовый к использованию инструмент. База отдельно, HTTP отдельно, формы отдельно. И несмотря на все успехи автоматического вывода типов, немалая часть кода занята перекладыванием данных.
Ок, как я понял, опять же, основной смысл не в языке, а в экосистеме и готовых решениях, где можно просто сесть и поехать. В том смысле, что теоретически же можно взять тот же C# поновее, объявить все нужные нам переменные и аргументы Dynamic, и можно будет писать customer.FirstName, а не customer["FirstName"].
Z>Я не могу приводить какие-то серьезные фрагменты реального кода. Книги по RoR? Их наверное масса, я изучал по туториалам, официальной доке и читая код фреймворка.
Z>Можешь посмотреть вот этот эпизод, мне кажется он близок к одной из тем, вокруг которых мы ходим.
Z>http://railscasts.com/episodes/416-form-objects
Z>Видео более 5 лет, некоторые вещи ушли вперед, но сам подход, как иллюстрация одного из способов решения может быть интересен. Я бы делал несколько не так, но для иллюстрации подойдет.
Ок, посмотрим.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Угу. Плюс архивная таблица, в которой лежат старые заказы. То есть, на самом деле, это три разных таблицы, потому что есть заказы разных типов — на услугу, на товар, на товар в электронной форме. S>Атрибуты и жизненный цикл у этих заказов — разные, но мы выставляем их через единую навигацию для упрощения тех клиентов, которым неважны подробности типа.
Надо будет эту логику организовать, так организуем. Не вижу тут никакой проблемы для RoR.
S>Круто. А кто проверяет, что в application.processed_at нет опечатки — ну там, что мы случайно не заменили в одном месте его на .handled_at?
В динамике все проверяют тесты и только тесты. Для этого случая достаточно иметь быстрый юнит-тест. Ну мне сложно представить себе насущную необходимость переименовывать поле в базе. Да, если это делается легко и просто, можно за этим следить и переименовывать как только душа захотела прекрасного. Но можно и работать с processed_at, его же не зря так называли.
S>Можем. Но мы храним не сами эти сущности. К примеру, сущность "адрес" вполне может лежать в таблице, но самостоятельного URL у неё нету — она публикуется только как часть более крупного документа. S>Или, к примеру, у нас события в календаре лежат в таблице в виде (begin, end, description), а наружу мы выдаём документы типа "расписание на день", где есть как слоты, занятые событиями, так и пустые. S>Сущность "слот" вообще не лежит ни в какой таблице.
И? В рельсах ты не обязан привязывать все к таблице.
S>Мы работаем с ним как с "одной сущностью" только в рамках внешнего API нашего сервера приложений. S>Как оно внутри там устроено — х.з. Очень, очень вряд ли там какая-то одна реляционая таблица — скорее всего, "бронирование" — это конгломерат записей из нескольких таблиц (root object, гости, история оплат, история переписки, ещё дофига чего). Может, там какой-то NoSQL, может, SQL, может, то и другое сразу. Наверняка есть какая-то интеграция с бэк-ендами гостиничных сетей (очень сомневаюсь, что клерки в Mariott вручную переносят данные из панельки booking.com в свою внутреннюю систему бронирования вручную). Вся эта кунсткамера выставлена наружу как обманчиво простой "ресурс".
Все верно. Я и не спорил с этим.
S>Я намекаю на то, что весь современный миддл-тир сводится к перекладыванию данных из одного источника в другой. И 90% ошибок — это ошибки, допущенные при согласовании вот этих протоколов. S>Идея статики — в том, что мы ловим такие ошибки статически. Что делается для этого в динамике? Ну, кроме интеграционных тестов?
А идея динамики — если не писать код, его не придется тестировать. Если пришлось писать, то да, только тесты. К сожалению контроль типов в статике не спасает от тестов, их все равно приходится писать и писать их даже немнго сложнее. А вот с возможностями "не писать код" у статики все гораздо хуже.
S>Ну так даже безо всяких сторонних систем, приложение — это интеграция "GUI" c "SQL", отношения между которыми достаточно произвольные. S>Да, офигенно круто, что нам не надо декларировать DTO — мы просто берём то, что нам вернул слой доступа к данным, и скармливаем в GUI, который выводит это дело в HTML. S>Но это же ровно то, что мы имели в любых доисторических фреймворках вроде ASP (без Net): просто биндинг по именам, recordset.GetValue('Name') и погнали.
Не совсем то, но чем-то похоже. Это же не значит, что RoR так же плох, как ASP.
S>Ок, как я понял, опять же, основной смысл не в языке, а в экосистеме и готовых решениях, где можно просто сесть и поехать. В том смысле, что теоретически же можно взять тот же C# поновее, объявить все нужные нам переменные и аргументы Dynamic, и можно будет писать customer.FirstName, а не customer["FirstName"].
Да, именно так. Я какое-то время был на распутье и пытался писать так же мало кода в .net. Даже Nemerle подключал для кодогенерации. Только у меня не взлетело, экосистему на коленке не создашь. .Net прекрасная платформа и C# один из моих любимых языков, но я уверен (и программисты со мной согласны), что мы бы сфейлили перенос на веб той системы по бюджету и срокам, если бы остались в рамках платформы.
Приведу пример. Я применил еще в винформс проекте рельсоподобные миграции схемы данных в году еще этак 2006. Лет за 8 разработки, доработка фич и фикс багов этого велосипедного решения заняло около 3-5 человекомесяцев (несколько видов поддерживаемых БД и постоянные хотелки программистов по поводу контроля схемы). Насколько я знаю, в .net сейчас есть штатный функционал для всего этого, не знаю его возможностей, но не суть. Суть в том, что только один модуль, который обеспечил возможность, бесплатно предлагаемую рельсами обошелся нам в кругленькую сумму. В какой-то момент, я осознал, что несколько сотен миграций мы могли написать и на чистом сиквеле, для каждой БД отдельно. Это было бы уныло, сложно писалось, тестировалось и поддерживалось, но по трудозатратам было бы вполне сравнимо. Впрочем для их прогона во всех необходимых сценариях все равно пришлось бы писать велосипед.