Pull to refresh

Comments 40

acts_as_api – хорошая штука, спасибо за упоминание. Но она решает проблему «месива» только частично. Оно переезжает в модели. Это само по себе уже очень плохая идея. Модели не должны сами описывать как их будет в JSON коряжить для разных контроллеров, – это нарушение инкапсуляции, которое на таких объемах информации вполне понятно к чему приведет.

К тому же, на мой взгляд, у них крайне сомнительный синтаксис. На момент когда его создавали 2 года назад это имело смысл. Сейчас – нет. По сути, мы без единой строчки кода собрали свой acts_as_api, но код лучше разделен и структурирован. А это и была цель – избавиться от каши.
Объясните далекому от Rails человеку, почему в модели нельзя создать метод, который возвращает необходимые данные, которые потом просто превращаются в JSON строку?
Потому же почему вы не пишете в модель метод, который будет возвращать HTML. REST-сервисы – такой же MVC. И проблемы такой подход создает те же.
При чем тут HTML. Модель возвращает данные, свои же.
В разных вариациях и обернутые в JSON-представление. Это и есть классический шаблон. Проще, чем HTML, но суть та же. Представьте, что вам надо вернуть сложную структуру. Причем в ней есть обычные if'ы. Это будут большие методы, которые будут заниматься сборкой представления данных под конкретную задачу. То есть вьюшки. А вьюшки не надо держать в модели :)
Как я понял, преобразование в JSON осуществляется всё же контроллером, а метод модели просто возвращает объект или хэш с данными в «нативном» представлении. То есть данные собирают, да, но их представление уже контроллер делает.
Преобразование в JSON производится, на самом деле, вьюшкой. Т.е. контроллер собирает модели, которые автоматически оборачиваются в декораторы и отдает в Jbuilder-представление. И Jbuilder сам дергает те поля (или наборы полей из декоратора), которые ему нужны.

Понятно, что хэш и JSON условно подменяемые понятия. Но вот _сама структура_ хэша – это и есть представление. Вот о чем речь :).
Все же не до конца понятно. Json — это же ассоциативный массив. Вы же не составляете массивы во view. Почему json должен составляться во view? В РНР это решается так: в контроллере составляется обычный ассоциативный массив $result. И на выход выдается json_encode($result).
JSON это не ассоциативный массив — это представление ассоциативного массива в заданном формате. В Rails можно сделать также render :json => data, но когда нужно отдавать сложные структуры данных такой способ становится не очень удобным.
Между понятиями «JSON» и «Ассоциативный массив» существует биективная связь. Поэтому можно, не придираясь к словам, говорить о том, что JSON — это ассоциативный массив. Суть не в этом. А в том, что почему-то сериализацию массива (это представление массива, не так ли?) почему-то принято делать в модели, а выше утверждается, что JSON (представление массива, но в другом формате) надо делать во view. Это и кажется мне нелогичным.

P.S. Что означает «сложные структуры»? Это какой-то сложный ассоциативный массив? Многомерный?
Вкладывающий в себя массивы других сущностей. С условиями – зависимость вывода того или иного атрибута от другого атрибута. Как я и писал в статье, под разные задачи набирается до 15 паршалов. Вы предлагаете в модели держать 15 методов, которые по-разному собирают поля этой модели и вложенных. Причем это не просто хэши, как может сначала показаться. Это еще и:

data.field.map{|x| x.foo = 'bar' if x.rocks? }


Благодаря Jbuilder и восприятию этого как представления, код органично распределяется по модели MVC.

А если следовать вашей логике, то собственно и контроллеры не нужны: HTTP-запрос принимает Rack, мог бы сразу модели отдавать, чего уж :).
Я не знаком ни с руби, ни с РоР, и не уверен, что хорошо понимаю некоторые ваши аргументы. Но описываемое кажется мне странным. Зачем view что-то знать об условиях и зависимостях атрибутов (передаваемых параметров)? Зачем делать по 1 методу на каждый паршиал? С какого момент спецификация JSON стала включать в себя if и map? Почему не используется наследование (тех же паршиалов, да и методов)?

Передергивание с веб-сервером, сразу отдающим ответ на запрос оценил, да.
Ну какое же это передергивание. Если все в модели – зачем вообще контроллер? Напишите еще один метод, который дергает те методы, что возвращают структуры. И вуа-ля. Весь CRUD-ресурс в одном классе. Только это жутко неудобно :).

По 1 методу на каждый паршал нужно потому, что структуры модель может возвращать разные. Это зависит от контекста применения. Именно про это в статье и написано. JSON в себя не включает map, это модификация хэша для добавления во вложенный массив поля по условию. И она вам понадобится в каждом втором методе. То есть если вы думаете, что весь метод – это красиво описанный хэш и такой метод будет один, то, увы, это не так.

А наследование тут вообще ни при чем ಠ_ಠ
Так ведь я и говорю о том, чтобы перенести логику из вьюхи в контроллер… о модели и речи нет. Хотя, вероятно, наше взаимонепонимание вызвано именно разными используемыми инструментами. Я говорю терминами symfony (которая, хоть, как говорят, и списана с РоР, но все же наверняка имеются нюансы).

Тем не менее, есть модель, которая знает все о своих данных и может их обрабатывать. Есть контроллер, который принимает входящие параметры и формирует данные для вью. В описываемом случае эти данные — готовый JSON. Если это API, то на этом все и заканчивается. Если нет, то уже готовый JSON передается в шаблон, где и используется на его (шаблона) усмотрение. Так зачем же пихать во вью принимаемые параметры, и заставлять вью работать с ними? Это же задача контроллера.

Наследование я упомянул здесь только потому что вас волнует DRY. А наследование в некоторых случаях помогает решить проблему of RY.
Давайте я поясню, этих JSON структур больше чем одна. То есть это не сериализация! И это очень важно понимать. Это именно формирование JSON _на основе_ модели. И таких JSON'ов в сложном проекте 10-15 на каждую модель. Загрязнять ими модель – плохая идея. Потому что эти 10-15 методов описывают формат общения с клиентом и к бизнес-логике отношения не имеют никакого.

Параметры принимаемые проходят через контроллер, это справедливо. Но обычно условия не от них, а от состояния модели. Никого же не смущает следующий такой псевдо-код в HTML:

if comments.count > 0
Комментариев:…
end

Тут условно то же самое. Этому во вьюхе самое место :).

Вы пишете, что готовый JSON передается в шаблон, а что с ним там делать? Это же просто строка. Которую чтобы корректно изменить, надо парсить.
Спасибо, так понятнее :)

Что делать с JSON в шаблоне?.. Тогда встречный вопрос: а зачем вобще тут JSON? Я полагал, что нужно сгенерировать некий JSON-ответ на запрос от внешнего сервиса, который знает что с ним делать (как его парсить). Если речь о взаимодействии в пределах одного приложения (AJAX), то тут вопрос: почему JSON? Почему не HTML, сгенерированный моделью? Если ответ настолько сложен, что его парсинг представляется проблемой, то возникает вполне законный вопрос: а нельзя ли сделать взаимодействие на основе более простых структур (тут был бы уместен конкретный пример).

Я правильно понимаю, что есть сложная-сложная модель (куча полей и взаимосвязей). И задача — выдать JSON (почему JSON, а не HTML? :) ), построенный по этой модели, но зависящий от входных параметров?

Мне сложно оценить выбранное решение, но я решаю эту проблему с помощью specialized queries (частный случай, когда модель — это сущность в БД, но покрывающая 99% случаев). И тут наследование как нельзя кстати ;)

JSON парсить не сложно, просто странно передавать в шаблон что-то, что надо парсить :). А в AJAX JSON отдается потому, что рендеринг происходит в браузере. Канал экономится и затрат на рендеринг HTML нет. JSON при генерации тратит куда меньше ресурсов.
Что вы делаете с JSON после того, как он сгенерится (где бы то ни было)?
Часть его – это API для банковской шины. Чать – забирает AJAX на клиенте. У нас вся генерация HTML происходит в браузере. Передается всегда только JSON.
чтобы сгенерировать HTML на основе JSON, его не надо парсить?
Так это уже конец процесса и происходит на клиенте :)
Собственно так и есть. СoachDB, например, на этом принципе и построен.

На примере веб-сервисов: Развитие js-фреймворков зачастую делает слой контроллера и view'а на стороне сервера лишним.
То, что делает контроллер и view, легко может сделать js-фреймворк на клиентской стороне: Запросить данные в виде json, преобразовать к виду, удобному для представления и отобразить соответстующим образом.

В вашем случае, если api и отдача данных в формате json первична по отношению к функционалу отображения данных средствами сервера, то может и действительно rails избыточный инструмент.
Хм… Из нашего опыта, городить api выдающие гигантские json-структуры бессмысленно и контрпродуктивно:

1) Документирование json-структур правращается в ад. В то время как компактные структуры при правильном подходе неплохо самодокументируют себя. Да и пользование таким api с компактными ответами существенно упрощается, по крайней мере для новичков.

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

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

4) Большие json-cтруктуры отъедают большое количество полосы пропускания и ресурсов на клиентских машинах, хотя по началу кажется, что такие структуры экономят процессорное время клиентов (мол, данные получили и вывели на экран). Но память в реальности куда более дефицитный ресурс. Пара сотен миллисекунд для компоновки ответа из нескольких json-структур на клиенте куда дешевле обходится, чем тусование страниц памяти между ОЗУ и cвопом, если вдруг структура не поместилась в уже выделенные страницы памяти.

5) Выдача данных большими json-структурами неоптимальна с точки зрения загрузки сервера БД.

Никакой очевидной выгоды от того, что вы пытаетесь выдать ответ «на все случаи жизни».

Когда программист выбирает техническое решение по реализации того или иного функционала, но по сути выбирает диспозицию внутри треугольника «ясность кода — надежность — скорость».

Создавая столь громоздкие json-структуры вы, на мой взгляд, необоснованно усложняете реализацию задачи, которая и так обычно не очень простая. А сложные задачи просто не решаются в силу определения, и требуют соответствующего количества кода. Используя DRY вы сможете сократить код в лучшем случае 10-15%, причем в ущерб скорости и надежности.

В общем, мое мнение, в таких случаях api и ответы наоборот необходимо дробить на минимальные семантически полные смысловые блоки данных. Посмотрите на идеологию организации данных в документо-ориентиованной MongoDB. Мне кажется это то, что нужно.
Частично с Вами соглашусь, но все зависит от задачи, например сходить 2-3 раза за несколькими структурами из Норильска проблему только усугубит.
Своп-память? Разве идет речь о сотнях мегабайт?
А так да, все так и есть.
Не только не усугубит, но и повысит надежность, поверьте. Могу это обосновать, но это займет много места и будет не по теме.
На счет свопа. Может быть и о сотнях мегабайтах, в статье об этом ничего не говорится.

И потом, редкая клиентская машина может похвастаться тем, что там выполняется только одно приложение. Даже в банкоматах обычно вертится больше одной задачи. Поэтому вполне возможен и своп.
В любом случае аллокация дополнительной памяти для приложения это достаточно дорогая задача. Не зря даже в наше время многие приложения грешат захватом памяти «про запас».
Сложные структуры != гигантские структуры. И, честно говоря, ваш совет звучит как «не надо создавать много таблиц в СУБД, надо мало». Вроде бы это и правильно, но реалии, они другие :). Это же от задачи зависит.
Ну и, строго говоря, там где нужно раздать много данных JSON весит сильно меньше HTML. Так что ребята из Норильска яростно плюсуют :).
:) Мой совет: Делайте декомпозицию структур, чтобы они были простыми и понятными. Принципиально упростить решение у вас вряд ли получится, но облегчить себе жизнь хоть как-то можно.

Лучше иметь много простых но легко понимаемых по отдельности структур, чем иметь две-три таких, в которых сам чёрт ногу сломит. Ведь чтобы состыковаться с вашим приложением, вашему коллеге придется с этим разбираться. Если он не сможет разобраться, то долбать он будет вас. )

То, что выбран JSON я как раз считаю правильным решением. Приятно удивлен тем, что не SOAP. В банковской среде это гм… очень любят и даже восторгаются им…
Совершенно справедливо. Эта статья, она ведь и есть про декомпозицию и правильное структурирование таких вот объектов :). Обычно если идти с меньших сущностей к большим все усваивается довольно хорошо.

А что до банков, JSON потом все равно на уровне транспорта приводится к SOAP обычно… Банки такие банки. Хотя SOAP не самое плохое, что у них есть. Там иногда ТАКОЕ встречается, что потом очень тяжело пользоваться карточками пластиковыми и вообще хранить деньги где-то вне дома :(
)))) Я вас отлично понимаю. Сам в своё время начинал карьеру в банке. )
> Каждая модель представлена CRUD-реурсом (в каждом по 3-4 расширяющих метода).
Можно чуть поподробнее, что за расширяющие методы? Имеются в виду какие-то дополнительные операции, помимо CRUD? А то гугление по extention method выбрасывает ссылки на C#-контент, что немного смутило.
я так понимаю имелось в виду чтото типа /posts/:id/comments
Либо /posts/:id/manage /posts/:id/hide /posts/:id/show /posts/:id/commit /posts/:id/approve
Вам ответили совершенно правильно. Именно это и имелось в виду :)
«Паршалы» — по-русски звучит довольно мерзко. Ухо режет. Может, стоит переводить как «партиалы? „Частичные“? „Частички“?
Ага, частички. А потом в примечаниях к переводу объяснять, что за частички такие)
Тогда логично именно partial -> партиал, партиалы. Не используя звучание английского названия, а только написание.
Ну да, по правилам транслитерации может так и стоило бы делать. Но я считаю, так часто случается потому, что это слова просто вырваны из английского языка, часто слышатся именно от англоговорящих людей, употребляются в соответствующей среде и не имеют никакого адекватного представления в русском. Мы ведь не говорим, чтобы далеко не ходить, «кукумбер» (cucumber) или «феатурес» (features).
Я очень большую часть времени говорю на английском, поэтому мне как-раз ухо режет «партиал». Оба этих варианта, что «партиал», что «паршал», не особо хороши. Но у слова «частички» есть другой важный минус: никто не поймет что это.

А вообще это очень странное чувство, переводить свою статью на родной язык и ощущать, что столь многого просто не можешь сказать с той же легкостью :\
Sign up to leave a comment.