Pull to refresh

Comments 24

Интересно… а после методов findById, all — тоже работает автозаполнение?
Есть ли какие-то примеры приложений на вашем фреймворке?
добавил ссылку на todo-mvc в начало статьи
Эмм. Бэкбон без вьюшек и кривоватым API?
почему без вьюшек, если охватить все, то сейчас там есть вьюшки, шаблоны, event bus, абстракция программной логики (а-ля джавовские интерфейсы с подменяемой реализацией), аякс абстракции, модули, API для работы с хэш-навигацией (на порядок лучше чем любая из известных мне реализаций, включая убогий angular), возможность загрузки сразу нескольких приложений на страницу, с разделяемой опять же хэш-навигацией, кроссдоменность на лету, подгрузка html-реализации тех же вьюшек и шаблонов. Просто это очень много всего, здесь я написал только про один из компонентов.
Кстати, чем API кривовато?
Кстати, чем API кривовато?

Как минимум, тем, что одна модель и их коллекция одинаковы в объявлении. Это прям таки антипаттерн («Золушкина туфелька», как подсказывает википедия), но, как минимум, это точно попадает в раздел «не делайте так».
«onUiBound» — а если я хочу разделять события по неймспейсам (задачи разные бывают), как поступать?

В чем удобство? Теперь можем из любого места доступаться до этих данных, например где-то еще, в не связанном с первым блоком коде

По сути, это — глобальная переменная, а о том, что они — зло — написано миллионы тысяч раз. (как, к слову, и о сигнлтонах).

Вот допустим, мне нужно иметь две модели (пользователь), никак между собой не связанные? Избыточно использовать список? Избыточно городить две одинаковые модели?
И это только по тому, что описано в статье.

P.S. Возможно в том и проблема, что в статье описано не полностью.

И да. Я всеми руками «за» то, чтобы не городить велосипед-клон бэкбона (потом дорастете до марионета), а потратить силы и время на дописывание уже существующих.
Ну и да. Не вижу, как тут реализовать наследование. А без него — сразу крест. Ну и опять же — где поддержка es6 классов, хотя бы в перспективе?

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

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

Про глобальность — во-первых модели это не переменная, это API, доступ к моделям происходит через функции. Таким образом недостатка «а кто это поменял» здесь нет — при отладке любой доступ легко отслеживается по стек трейсу, либо нажатием ctrl+alt+f7 в той же Идее, чего никак не скажешь про другие фреймворки. Синглтон в приложении к моделям это всего лишь объект, встречающийся в приложении один раз, а не тот классический статический объект.

Наследование в функциональном языке — до сих пор делается костылями. И не использование этих костылей я не считаю недостатком. А es6 классы это просто чуть подкрашенная обертка вокруг все тех же костылей. Давайте уже честно писать на функциональном языке функциями. Но если мне все же захочется унаследоваться сейчас, напишу вот так:
var modelBase = {...}
var modelInherited = $.extend({}, modelBase, {extra-properties-for-child});

Но вообще метод add или updateAll возвращает объект модели, и при честном использовании классов es6 — я просто создам этот объект в коде и верну его (для репозиториев). Можно сказать, что модель это java reflection, если знакомо — и по нему воссоздается класс объекта.

Про двух пользователей чуть позже.
Давайте уже честно писать на функциональном языке функциями

Давайте не называть ООП язык чисто функциональным. То, что там прототипно-ориентированный подход не означает, что это не ООП, тем более, что это чисто-функциональный.

Про глобальность — во-первых модели это не переменная, это API, доступ к моделям происходит через функции.

Через такие же глобальные. От того, что ты не напрямую получаешь её, а через функцию — лучше от этого не становится. Опять же. В одном месте мне нужен пользователь с ID = 1, в другом — с ID = 3, а они синглтоны… Впрочем, вы обещали это позже рассмотреть.

Как раз эта схожесть подхода катастрофически удобна, хотя и ломает стереотипы

Имеется ввиду то, что две абсолютно разные по идеологии абстракции используются с одним интерфейсом, вдобавок, неявно определяют. Написали update — получили один экземпляр. Написали fetch (или что там, в примерах в статье не вижу) — получили коллекцию. Взорвали себе мозг, забыв в какой-то момент, один у тебя объект, или репозиторий.

«во-первых» а где во-вторых? простите, не удержался.

Ну а теперь о схожести с бэкбоном.

app.models.loggedUser = {
    // auto-added function, declared for readability
    update: function(obj) {},

    // model fields
    firstName: function(val) {},
    lastName: function(val) {},
    id: function(val) {}
  }

и
const User = Backbone.model.extend({ 
  firstName: function() {..}
});

Правда, в чем схожесть между двумя фреймворками, решающими одинаковую задачу похожими методами?

так как там приходится писать много избыточного кода на реализацию всех функций модели

Каких же? Тех же, что и у вас, реализующих бизнес-логику? Системные функции типа update, save и прочее — есть из коробки.
Сразу хочу сказать «спасибо за комментарии», все написанное очень ценно и интересно.
По делу — Например, в бэкбон вот так:
book.set("title", "A Scandal in Bohemia");

а здесь вот так:
book.title("A Scandal in Bohemia");

Выглядит похоже. Но во втором случае есть автозавершение от IDE и это гарантирует что я не описался в строчной переменной и сэкономило мне от секунды до нескольких написания. Казалось бы — мелочь, но сколько времени экономится и потенциальных ошибок обходится. Аналогично get.
Вообще когда я начинал jiant — я не смог найти ни одного дружащего с автозавершением js фреймворка, поэтому начал свой )
По объявлению интерфейса — В джаве тоже очень похожая запись будет интерфейса. А в С# еще больше.
И вот за этими "..." внутри бэкбон функции скрывается тоже ведь строчка кода, которую надо написать или скопировать. Это объявление не пустое.
Насчет изобретения велосипеда — Форду или кому-то еще когда-то не понравились все имевшиеся на тот момент автомобили и он сделал свой. И неплохо получилось.
Взорвать мозг, забыв что там, довольно сложно, так как всегда можно взглянуть на объявление. Плюс по смыслу обычно всегда понятно, не знаю почему, может проектировать удачно выходит. Уже название модели подсказывает что это такое и как используется.
book.set(«title», «A Scandal in Bohemia»);

Не поспоришь — это косяк бэкбона, который меня подбешивает. Впрочем, очень небольшой патч позволяет избежать этого.
И вот за этими "..." внутри бэкбон функции скрывается тоже ведь строчка кода

А в вашем случае нет? Что в бэкбоне, что в jiant — там же бизнес-логика, естественно там есть код. А стандартные есть всегда
нет кода, в этом и фишка — просто пустые функции, и find, list тоже. Если речь о сеттерах/геттерах конечно или о поиске по коллекции
Великая благодать Jiant'а в том что вместо программирования мы проектируем, и в конце получаем работающий код.
Попробую этот подход и здесь.
Два пользователя — допустим, такой сценарий — пользователь, пишущий комментарий, и пользователь, опубликовавший запись )
Они идентичны по параметрам, поэтому да, один репозиторий, допустим такой:
user: {
  add: function(obj) {},

  name: function(val) {},
  id: function(val) {}
}

Мы уже видим что у нас в приложении есть объект пользователя с именем и идентификатором, далее есть варианты на выбор, какой больше соответствует религии данного программиста:
1) Объявим модель env с полями author, reviewer и выставим туда нужных пользователей
  env: {
    author: function(val) {},
    reviewer: function(val) {}
  }
  jiant.onUiBound(app, function($, app) {
    var m = app.models;
  // откуда-то получили, скажем с сервера данные об этих пользователях
    m.env.author(m.user.add(authorData)[0]);
    m.env.reviewer(m.user.add(reviewerData)[0]);
  });

2) Аналогично 1му, но методы доступа помещаем прямо в user:
  user: {
    author: function() {return this.all()[0]},
    reviewer: function() {return this.all()[1]}
  }
 ....
  m.user.add([author, reviewer]);

3) Добавить поле пользователю role, выставлять его и искать по нему
  user: {
    role: function(val) {},
    findByRole: function(val) {}
  }
  ....
  m.user.add(...);
  m.user.findByRole("author");

3й способ расширяем, 1й почти как новые объекты, но вместо new — add, плюс перед new — возможность увидеть сразу список полей модели
И это «меньше чем в бэкбоне» и изящное решение? У нас с вами сильно разные представления об изящности…

К слову. Допустим, вам таки нужно два экземпляра с одинаковым id. Например, вы хотите посчитать диф между старой и новой версией (два человека одновременно редактируют запись). А в jiant заложено на уровне архитектуры невозможность такого (на сколько я понимаю — исходили из идеи «одна сущность может быть только в одном экземпляре). Да, можно сделать модель model_old, model_new — но это костыль
Тогда мне можно код аналогичный бэкбона, для сравнения? Со всеми декларациями переменных.
Насчет одинакового ида — как раз здесь это плевое дело — при обновлении переменной передаются старое и новое значения. Допустим, мне прилетело по вебсокетам обновление на запись, тогда у меня сработает вот такой код:
  app.models.record.text.on(function(record, newText, oldText) {
    ...
  }

Где oldText — текущее значение, newText — новое. Подавляющее большинство задач в jiant решается на порядок меньшим объемом кода, это кстати из отзывов реальных людей (что-нибудь типа «почему тут так мало кода»), попробовавших на нем писать, а не реклама.
const User = Backbone.Model.Extend({
  url: '/users.json'
});

let author = new User(id); // можно передать obj
let reviewer = new User(id);


Сравнение тут так же очевидно, покуда у вас есть два объекта, которые нужно сравнить. Например, если пришел с сервера:
const User = Backbone.Model.Extend({
  url: '/users.json',
  events: 
    change: function(arg, old_val, new_val) { } // с точностью до аргументов
    'change:name': () => {..} // следить за изменением только name
});


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

Вы же предлагаете новый молодой фреймворк с сомнительными преимуществами (как минимум, из этой статьи их не видно совершенно) с нулевым комьюнити. Да, попытки улучшить мир — похвальные, сделать разработку удобнее и проще — отличное дело, а запускать своими силами, не будучи гуглом или фейсбуком свой фреймворк ужасно сложно, в данном деле я вам желаю успеха. Но, к сожалению, совершенно не видно коммерческой ценности против прочих решений, коих сейчас миллионы.
Я попытаюсь ) Продолжу писать о других компонентах фреймворка.
Лучше попытаться и обломаться чем не попытаться.
По-крайней мере ниша нормального фреймворка на javascript сейчас пуста, то что доминирует — такое убожество, что просто приглашает попытаться.
Если мне удастся найти несколько человек, заинтересованных в новом фреймворке, это уже комьюнити для начала.
Присоединяйтесь, хотя бы попробуйте )
Если хотите более умные бэкбон модели то предлагаю вам посмотреть на ampersand-model. У них есть и другие компоненты, но мы используем именно модели в ангуляр проекте.
изящество в том что автор и ревьюер инкапсулированы внутри модели, и для внешнего использования вызывается всего-лишь
env.author()
или
env.reviewer()
это действительно удобно и изящно
Великая проблема в том, что на рынке полно хороших программистов, а вот адекватных проектировщиков как раз таки нет.
Увы, я тоже встречал таких «хороших» (в кавычках) программистов — трудолюбивых (без кавычек) и готовых 8 часов писать 100 строк кода вместо того чтобы подумать 1 час и потом за 10 минут написать 3 строки. К счастью поувольняли(сь), но до сих пор мы за ними разгребаем их «творения». А многие могли бы делать хорошо, но не хотят думать.
После них не работает к сожалению.
Касательно примеров — часть коммерческие приложения и чтобы дать на них ссылку мне надо получить разрешение. Из того что доступно — достаточно крупное — игрушка http://frombeyond-game.com, на которой собственно отлаживалась и проверялась на жизнеспособность в произвольном окружении концепция, домашняя страница и сама игра там реализованы полностью на jiant.
Также есть локально реализация todo-mvc, в ближайшие дни выкладываю на github (думал уже выложил ) )
Много разных моделей проверял смотрел, для мeня лучше всех кажеться ampersand-model. Это как бэкбоун на стероидах. Завернули у себя в ангуляровский сервис и все очень хорошо. Мне не совсем понятно как у вас реализованы derived fields, кэшируемые и нет. Есть ли у вас понятие проксированя модели в REST API? Если да, то как определаються поля которые нужно передать на сервер а какие нет? Проверка типов и валидация? Значения по умолчанию?
Почти всего этого нет, не было необходимости в реальных проектах, а добавлял только то что нужно или что используется чаще чем в 10% случаев (как правило 90% функционала фреймворков работает для 10% юз кейсов, ну и 10% для 90%, этого хотелось избежать)

1) derived — это как раз функции с реализацией, типа
fullName: function() {return this.firstName + " " + this.lastName()}


2) кэша на них нет, ситуация где значение такого поля используется больше 1-2 раз мне так с ходу не придумывается и не попадалась, но наверное бывает

3) таким образом как в ampersand-model передача на сервер не сделала, я думал над этим, но пока не ощутил необходимости в таких функциях именно в модели. Собственно отправка модели на сервер выполняется так:
  app.ajax.doSearch(app.models.searchParams, callback);
  // или
  app.ajax.save(app.models.listing.all(), callback);
  // или
  app.ajax.save(app.models.listing.listByTp("some type"), callback);

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

4) отправляются все геттеры модели кроме объявленных как jiant.transient — эти на сервер не посылаются (и кроме derived)

5) задача валидации не входит в модель, для этого есть jquery плагин validate

6) проверки типов тоже нет, в разрабатываемых проектах ни разу не возникло ситуации чтобы я подумал что она нужна

7) значения по умолчанию — вот это изредка возникает, и этого сейчас нет, чтобы установить какие-то начальные значения, нужно их ставить через сеттеры или через update()

А вообще именно ampersand-model мне не попадался, искренне благодарю за наводку. Он действительно хорошо расширяет бэкбон и надо будет поизучать. Единственно — синглтон приложение (если я верно понял) — это несерьезно. У нас повсюду минимум два приложения крутится на страницах — одно это чат, другое основное, а кое-где и по 3-4, с разных доменов, и они прекрасно друг с другом уживаются, включая совместную работу. Ну и хэш навигация у них как почти везде сделана явно в лоб. В этом jiant сильно обогнал их.
в примере к 1 пункту опечатка, должно быть
  fullName: function() {return this.firstName() + " " + this.lastName()}

Привык что Идея авто-завершает функции скобками и не поставил на автомате )
Sign up to leave a comment.

Articles