Сладкая жизнь, или Создание веб-приложения без написания кода
Создадим простую социальную сеть для общения гостей на виртуальной вечеринке. Зарегистрированные пользователи смогут заводить друзей, провозглашать тосты, обсуждать и делиться ими с другими участниками. В классической MVC архитектуре это решается с помощью написания соответствующих моделей, контроллеров и представлений. Но попробуем обойтись без кода.
Для этого воспользуемся декларативным фреймворком Evado, в котором предметные сущности и связи между ними описываются через веб-интерфейс. Минимальное окружение необходимое для работы — это Node.js и база данных MongoDB. Среда разработки — Visual Studio Code. Впрочем последнее необязательно, если писать код не планируется.
Из гитхаба копируем шаблон приложения в локальную папку /party
(в дальнейшем все пути указываются относительно нее) и выполняем установку зависимостей.
npm install
Файлы конфигурации находятся в папке config
. При запуске приложения выбирается файл, в зависимости от значения глобальной переменной NODE_ENV
. Каждая из конфигураций наследует параметры из config/default
.
Изменим название приложения и базы данных (по умолчанию подключение происходит на localhost:27017 без пароля). Включим русский язык в компоненте i18n. Все, на этом настройка закончена. Далее выполним скрипт установки:
NODE_ENV=development node console/install
Затем запускаем приложение (запускать можно и из Visual Studio — конфигурация Start app):
NODE_ENV=development node console/start
В режиме development
приложение доступно по адресу http://localhost:3000
. Войти можно под пользователем Adam с правами администратора, который был создан при установке из настроек по умолчанию.
Email a@a.a
Пароль 123465
Краткий обзор фреймворка
Фреймворк Evado состоит из нескольких базовых модулей и компонентов, которые определяются настройками конфигурации. Все модули имеют унифицированный веб-интерфейс с темой AdminLTE.
В модуле "Студия" создаются и редактируются метаданные, которые описывают сущности (доменные модели) нашего приложения и связи между ними. Актуальные данные хранятся в виде JSON файлов в папке metadata/app
.
В модуле "Офис" происходит эксплуатация приложения. Создаются и редактируются объекты на основе метаданных.
В модуле "Администрирование" осуществляется управление системными пользователями, правами доступа и другими параметрами приложения.
Подготовка вечеринки
Первым делом позаботимся о гостях вечеринки. Переходим в модуль "Студия" и создаем класс "Участник". Каждый участник должен быть напрямую связан с системным пользователем. Для этого добавим обязательный и уникальный атрибут "Пользователь".
На нашей вечеринки будут провозглашаться тосты. Создадим класс "Тост" со строковым атрибутом "Заголовок" и текстовым "Содержание". Чтобы привязать тост к участнику, добавим ссылочный атрибут "Автор". Ссылочный тип определяет, что его значение является ссылкой на другой объект. В данном случае на объект класса "Участник".
Не всегда тост предназначен широкой огласке. Иногда это еще черновик, и автор только решает, как ярче преподнести свою мысль. А иногда всю глубину тоста сможет понять только ограниченный круг людей, и видеть всем его необязательно. Для этого добавим строковый атрибут "Доступ". На вкладке "Перечисления" создадим перечисление с элементами значений доступа:
- Никому кроме автора
- Только друзьям
- Для всех участников
Мудрые, нелепые, провокационные или смешные высказывания всегда вызывают ответные эмоций. На вечеринке должна быть возможность обсуждать тосты. Для это создадим класс "Комментарий" с обязательным текстовым атрибутом "Текст" и ссылочными атрибутами "Тост" и "Автор". В них будут храниться ссылки на тост, к которому относится комментарий, и участника, создавшего комментарий.
Кроме значений созданных атрибутов, объекты сущностей содержат некоторые системные данные. Например, дату создания, дату изменения, создателя объекта и другие. Для отображения их необходимо описать в метаданных.
Создадим атрибут "Дата создания" с кодовым именем "_createdAt" и типом представления "Локальная дата и время". Локальная дата означает, что будет учитываться часовой пояс.
Атрибут с кодовым именем начинающимся с подчеркивания относится к системным и доступен только для чтения.
Чтобы подружить двух людей необходимо получить согласие обоих. На нашей вечеринке будем придерживаться этого равноправия. Один участник создает дружбу, другой может ее принять или отклонить. Для этого создадим класс "Друг", который и будет определять дружеские отношения. Добавим обязательные ссылочные атрибуты "Приглашающий участник" и "Приглашаемый участник". Для определения состояния дружбы добавим строковый атрибут "_state" с типом представления "Состояние".
Во фреймворке Evado реализован конечный автомат для объектов сущностей. Каждый объект находится в определенном состоянии и может быть переведен в другое по указанным переходам.
Переходим на вкладку "Состояния" и создаем три состояния:
- Ожидание решения (назначаемое по умолчанию)
- Дружба принята
- Дружба отклонена
Переходим на вкладку "Переходы" и создаем пару переходов:
- Принять дружбу
- Начальные состояния "Ожидание решения" и "Дружба отклонена"
- Конечное состояние "Дружба принята"
- Отклонить дружбу
- Начальные состояния "Ожидание решения" и "Дружба принята"
- Конечное состояние "Дружба отклонена"
После принятия решения у приглашенного участника останется возможность передумать и изменить дружбу. Приглашающий же, как создатель, может в любой момент ее удалить.
Обратные связи
Как найти пользователю все его комментарии, если связь комментария с пользователем хранится в классе "Комментарий"? Для этого существует обратная ссылка, которая определяет связь через атрибут в ссылочном классе.
Чтобы отобразить все комментарии к тосту, добавим обратную ссылку "Комментарии" на класс "Комментарий" и атрибут "Тост". Чтобы отобразить все тосты участника, добавим обратную ссылку "Тосты" на класс "Тост" и атрибут "Автор".
Для отображения подтвержденных участников-друзей… И здесь предчувствие наносит первый удар, что одними декларациями обойтись не удастся. Действительно, чтобы найти таких участников необходимо:
- во-первых, найти друзей, которые находятся в статусе "Дружба принята"
и текущий участник является либо приглашающим, либо приглашаемым; - во-вторых, нужно найти участников (кроме текущего), которые связаны с найденными друзьям.
Через веб-интерфейс можно задать связь только по одному атрибуту или наложить дополнительное условие. Для сложного отношения придется написать свою реализацию, и подключить ее в поле "Фильтр":
{"Class":"component/meta/relation/FriendMembers"}
Экспорт метаданных
Для того, чтобы созданные метаданные попали в приложение необходимо их экспортировать. Кнопка экспорта (импорта) расположена на верхней панели модуля "Студия". Указать можно любую целевую папку, но учтите, что приложение будет загружено только из metadata/app
. После успешного экспорта приложение готово для эксплуатации в модуле "Офис".
Регистрация участников
Для самостоятельной регистрации пользователей на сайте в файле конфигурации console/default
в секции params
ставим
enableSignUp: true
Для нового пользователя необходимо создать объект класса "Участник". Для этого в модуле "Администрирование" создадим слушателя события регистрации.
События: auth.register
Описание: Создать участника при регистрации пользователя
И добавим к нему обработчик.
Кодовое имя: memberInstantiation
Описание: Создание объекта "Участника"
Конфигурация: {
Class: 'evado/component/handler/MetaClassInstantiation',
className: 'member'
}
Права и обязанности
Базовой возможностью любого многопользовательского приложения является разграничение прав доступа. Фреймворк Evado реализует систему управления доступом на основе ролей.
Пользователю могут быть назначены одна или несколько ролей. Каждая роль содержит разрешения, которые описывают то, что можно сделать. Например, создать объект или получить доступ к модулю. На разрешение можно наложить правило, которое определяет будет ли данное разрешение срабатывать. Например, если на разрешение редактировать объект, наложить правило, проверяющее является ли текущий пользователь создателем объекта, то только автор получит право редактирования.
Если вы лишились доступа через веб-интерфейс (например удалив права администратора), то внести изменения можно через консольный скрипт console/security.
В модуле "Администрирование" перейдем в раздел "Безопасность — Роли". Изначально в шаблоне приложения определены три роли:
- администратор (полный доступ к данным)
- пользователь (роль для идентифицированных пользователей)
- гость (роль для анонимных пользователей)
Для нашей вечеринки этого вполне достаточно. После входа участника роль "Пользователь" будет назначаться ему по умолчанию, без необходимости задавать ее явно.
Чтобы изменения безопасности вступили в силу необходимо выполнить перезапуск (кнопка в верхней панели).
Определим требуемые разрешения для участника:
- создавать, редактировать и удалять собственные тосты
- просматривать тосты, к которым разрешен доступ
- редактировать и удалять собственные комментарии
- просматривать и создавать комментарии к тостам, к которым разрешен доступ
- просматривать участников и друзей
- создавать и удалять собственных друзей
- редактировать дружбу, если является приглашенным участником
Здесь снова не хватает одних лишь описательных действий через веб-интерфейс. Например, чтобы задать правило для чтения разрешенных тостов, нужно определить, что у тоста установлен доступ "Все" или установлен доступ "Друзья" и текущий пользователь является подтвержденным другом автора тоста. Для этого необходимо написать свою реализацию правила.
{"Class":"component/meta/rbac/rule/ToastRule"}
Заключение
Регистрируемся под новым пользователем, переходим в модуль "Офис" и пробуем на вкус весь задуманный функционал. Вечеринка состоялась, а вот совсем без написания кода не получилось. Даже в таком относительно простом приложении встретились проблемы, которые невозможно решить через универсальный веб-интерфейс. Если усложнить структуру описания сущностей, чтоб включить больше возможностей, то она начнет уступать в простоте и оптимальности императивному коду. Может сборка из "кубиков" не типового приложения — это утопия?
P.S.
Репозиторий готового приложения. Можно запустить в докере.
Онлайн демо. Войти как Боб:
Email: b@b.b
Password: 123456
lair
И вот сразу вопрос: а зачем?
modestguy
И по какому случаю вечеринка? :)
apxi
А зачем с кодом если можно без кода?
lair
Затем, что "без кода" — это не "выкидываем шаг с кодом", а "заменяем шаг с кодом на что-нибудь другое". А зачем?
apxi
Затем, что иногда без кода проще чем с кодом.
lair
Иногда, и это очень важное слово. Оно не отвечает на вопрос "зачем мы пробуем обойтись без кода в этом случае".
apxi
Затем, что возможно в данном случае это опраданно.
lair
Ну вот я и спрашиваю — чем оправдано?
therb1
Тем что некоторым частям ИТ сообщества не хочется писать на JS а веб нужен. Например в небольших проектах
lair
Ну так не обязательно писать на JS, чтобы получить веб.
therb1
В таких вопросах я предпочитаю придерживаться мнения "рынок рассудит".
Если проект не сыщет популярности, он будет забыт как миллионы других проектов.
А если сыщет то кто мы такие и чем он нам мешает, что мы его не любим или считаем не правильным.
lair
А я вроде ничего не говорю о проекте. Я просто спрашиваю, зачем в данном конкретном случае "мы пробуем обойтись без кода".
therb1
Ваш вопрос не коректен.
Так как лично вам никто не предлагает пользоваться данным продуктом, то вопрос должен стоять не "Зачем?" а "Почему?".
А ответом на него будет потому что нам в нашей жизненной ситуации так удобнее, но возможно вы тоже попадете в такую ситуацию и удобно будет уже вам.
lair
А при чем тут лично я?
Почему? Почему смена пользователя с "мы" (в статье) на "я" меняет вопрос с "зачем" на "почему"?
therb1
Если вы посмотрите внимательно то в статье написано "Но попробуем обойтись без кода."
То есть тут происходит то о чем я говорил, человек в определенной ситуации решил обойтись без кода и ему это удалось.
После чего он поспешил поделиться наработкой, за что ему несомненно респект.
lair
Если вы посмотрите внимательно, в своем первом комментарии я задаю вопрос именно к этой фразе.
Зачем мы пробуем обойтись без кода?
therb1
Вы задаете вопрос "а зачем?"
"Мы" вы примешиваете уже позже в ответе на мой вопрос.
И ответ здесь в том что это "они" пытаются обойтись без кода, а не "мы".
Для них это правильный вариант.
lair
Пожалуйста, не надо мне приписывать то, что я не говорил. "Мы" было в изначальной цитате.
Почему для "них" это правильный вариант?
therb1
Скриншот пожалуйста, я не вижу "Мы" у автора в тексте.
lair
В русском языке слово "попробуем" не подразумевает никакого другого варианта. Первое лицо, множественное число. "Мы".
therb1
Как бы то ни было. Ответом было и остается:
Потому что нам в нашей жизненной ситуации так удобнее, но возможно вы тоже попадете в такую ситуацию и удобно будет уже вам.
lair
Ну так я и хочу понять, почему "вам" в вашей жизненной ситуации так удобнее. Точнее говоря, я хочу понять, в какой же жизненной ситуации так удобнее.
therb1
В той ситуации когда у тебя есть один разработчик на JS и тонна людей без знания JS. Но тебе нужно что бы они тоже могли что то да сделать на сайте.
lair
… но при этом вам не нужно, скажем, версионирование всего того, что они "делают на сайте"?
therb1
Просто почитай как создавался Django.
Ставлю пиво тут мотивация такая же
lair
Я, вроде бы, задал конкретный вопрос. Но нет, так нет.
therb1
Нет версионирование на данном этапе развития не нужно.
lair
Ну вот видите, как можно много выяснить о ситуации:
Теперь любой желающий (вроде меня) может примерить эти условия на себя и понять, подходит ли ему такая ситуация.
therb1
Вы явно не тот человек, под которого рассчитано данное решение.
apxi
Иногда вообще не обязательно писать чтобы получить веб, для этого собственно и делаются подобные проекты.
lair
Я бы понял, если бы подобные проекты делались, чтобы ничего не делать, и получался веб. А тут речь идет о том, что что-то делать все-таки надо. Разумный вопрос — почему, собственно, считается, что лучше делать это "что-то", а не писать код?
apxi
"Что то" делать всегда надо.
Вы код всегда пишите или все таки пользуетесь другими инструментами в виде мыши или сенсорного экрана?
lair
Нет, не всегда.
Но, как иллюстрация моего тезиса, чтобы написать этот комментарий, я воспользовался текстом, а не мышью или сенсорным экраном. И чтобы проставить в нем форматирование — тоже.
apxi
Вы выбрали самый удобный способ, удобный именно для вас. Вот другим удобно форматирование мышкой делать, а сайты конструктором собирать, а еще это намного дешевле, чем нанимать программера, дизайнера и т.д.
lair
Удобство — штука очень субъективная. У вас никогда так не было, что вы думали, что вам удобно, а потом вам показывали, что какие-то вещи намного удобнее делать иначе?
Вот, например, в тексте очень удобно найти все вхождения слова "участниками", да и заменить их на "посетителями". А в интерфейсе конструктора я даже и не знаю, как.
Это, скажем так, считать надо. Причем в долгосрочной перспективе.
apxi
Попробуйте посчитать, сильно удивитесь.
lair
Покажете пример расчета? Потому что я в основном наблюдаю случаи "окей, мы попробовали, а теперь нанимаем программера".
apxi
Тем что не нужно звать программера и пользователь сам может сделать. Сами не могли догадаться?
lair
"Догадаться" я могу до чего угодно, только это так и будет догадкой. А если я буду использовать эту догадку как базу для размышлений, то немедленно получается следующее — шаги вида
в моей системе ценностей не удовлетворяют критерию "не нужно звать программера и пользователь сам может сделать". Это вот то, до чего я догадался.
apxi
Получается по вашему каждый сам себе с нуля должен был написать?
lair
Нет, не получается. Я не понимаю, как вы перешли от того, что я сказал, к тому, что вы сказали.
apxi
Прочитайте внимательно ваш первый коммент и хорошенько подумайте.