Философия Ember.js

В последнее время в вебе идет тенденция к «утончению» сервера и «утолщению» клиента. С каждым днем вакансий Full-stack разработчиков становится все больше, а чистого бэкенда все меньше. Последние 2 года я работаю разработчиком Ruby on Rails и в скором будущем без работы остаться не хотелось бы. Поэтому я начал рассматривать варианты изучения клиентского фреймворка.

Вариантов было несколько:

  • Meteor
  • Angular
  • Ember

Но остаться должен только один. Meteor предлагает интересную концепцию – общий код клиента и сервера, но он пока сыроват и мне не хотелось оставлять прекрасный язык Ruby. Поэтому Метеор отпал. Так как Ember был похож на Rails (магия, convention over configuration), то был выбран именно он. Помимо этого, очень симпатично выглядел шаблонизатор Handlebars по сравнению с директивами Angular.

Выбор сделан. Вот тут и начались проблемы.

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

Ember называют MVC фреймворком, поэтому я ожидал увидеть что-то похожее на Ruby on Rails и классический MVC. Но не тут то было! Помимо модели, представления и контроллера (которые делают совсем другие вещи чем на сервере), здесь было много разных вещей: компоненты, маршруты, адаптеры, сериализаторы, шаблоны, хранилище.

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

Жизненный путь запроса


image

Рассмотрим схему более детально.

Точка входа


Приложение у нас одностраничное, так что точка входа у нас одна — index.html. Все переходы будут делаться с помощью якоря или history api. Все пути будут рабочими, то есть вы можете легко добавить нужную страницу в закладки и контент будет доступен по ней.

Маршрутизатор


Первым делом у нас работает Router. Именно он выбирает что делать дальше в зависимости от адреса и передает управление указанному в нем маршруту.

Маршрут


Route обрабатывает входящие данные, например параметры url, и обращается к модели или моделям. Он является связующим звеном между данными(Model) и их обработчиком (Controller).

Модель


Модели – это наши сущности, например в блоге – пост, пользователь, комментарий. Здесь уже используется не чистый Ember, а его дополнение – Data.
Для того чтобы получить указанные объекты есть 2 варианта:

  1. Получить их с помощью API.
  2. Получить из локального хранилища, в которые данные были добавлены при прошлом запросе в API.


При работе с хранилищем все просто – данные там лежат уже в виде объектов и при запросе достаются оттуда, а вот для работы с API используются еще 2 сущности: адаптеры и сериализаторы.

  1. Адаптеры задают правила работы с API, например получить все посты – GET /posts, а обновить пост – PUT /posts/1.
  2. Сериализаторы разбирают json-ответ сервера и устанавливают формат json-запроса.


Контроллер


Когда мы получили данные, мы можем приступить к их обработке. Именно в контроллере описываются вычисляемые свойства (computed properties). Контроллеры бывают нескольких видов:
  1. Controller – обычный контроллер, например для статичных страниц.
  2. ObjectController – для представления одного объекта.
  3. ArrayController – для представления массива объектов, может иметь еще вложенный ObjectController для каждого объекта(например для вычисляемых свойств каждого объекта) [1]

Представление


После этого необходимо отрисовать наши данные. Тут нам приходят на помощь шаблоны, представления и компоненты. Давайте сначала поговорим о шаблонах – участках html кода в который вставляются наши данные. Они могут содержать партиалы, компоненты и представления.

Теперь поговорим о представлениях и компонентах. Компоненты являются наследниками представлений, поэтому и то, и второе – это повторяемые участки кода. В связи с скорым переходом к версии 2.0 [2] нам советуют использовать лишь компоненты.

Components – целостные участки кода, отвечающие за одну функцию и которые будут использоваться в разных местах. Возьмем пример из жизни: мне необходимо было чтобы длинный текст автоматически сворачивался и появлялась кнопка «Развернуть». Именно для этого я использовал компоненты.

Партиалы – это те же самые шаблоны, которые вставляются в другие шаблоны, к ним все это относится точно так же.

Действия/события


Теперь необходимо немного рассказать про действия и action bubbling – цепочку действий.
Действия – то что происходит при определенных событиях(нажатию на элемент, отправку формы). Они описываются в контроллерах, маршрутах, представлениях, компонентах.
Рассмотрим небольшой участок кода:

// index.hbs
<h1 {{action 'doSomething'}}>{{post.title}}</h1>

// index-controller.js
App.IndexController = Ember.Controller.extend({
  actions: {
    doSomething: function() {
      console.log('Вы только что нажали на заголовок')
    }
  }
})

При клике на заголовок это событие передастся в соответствующий контроллер и там обработается – в данном случае выведет надпись в консоль браузера.

Action Bubbling

Action bubbling – это передача события вверх по цепочке если не был найден обработчик в маршруте/контроллере.
Пусть у нас будет такие маршруты, контроллеры и представления:

// post-route.js
App.PostsRoute = Ember.Route.extend({
  actions: {
    doSomething: function() {
      // 1
    }
  }
})

// posts-controller.js
App.PostsController = Ember.ArrayController.extend({
  itemController: 'post'
  actions: {
    doSomething: function() {
      // 2
    }
  }
}) 

// post-controller.js
App.PostController = Ember.ObjectController.extend({
  actions: {
    doSomething: function() {
      // 1
    }
  }
})


// posts.hbs
{{#each post in controller}}
  <h1 {{action 'doSomething'}}>{{post.title}}</h1>
{{/each}}


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

Вот то же самое в виде схемы:

image


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

P.S.: Если это будет интересно, в следующей статье я расскажу про написание приложения на EmberJS, интеграцию с Ruby on Rails, дополнительными пакетами и Ember CLI.
Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 30

    +1
    Ember хорош, но в тоже время «магия» иногда приводит к значительным остановкам, а некоторые вещи нельзя сделать до определенной версии Ember.

    ember-cli прикольная штука, благодаря тому, что:
    * унифицирует структуру приложения еще жестче и облегчает работу новичкам
    * будет частью 2.0+ и поддерживается core разработчиками
    * предоставляет инфраструктуру и для тестов сразу

    но:
    * скорость (по итогу вынес tmp на RAM disk)
    * разные дополнения разного уровня «деталей реализации», что может вылиться в необходимость или делать свой похожий или патчить чужой
    * необходимость прописывать, что именно мы складываем из bower_components после brunch выглядит излишним

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

      Реши недавно освоить этот «замечательный» фреймворк. Прочитал документацию, начал делать проект. Сначала был в восторге т.к. все действительно делалось просто и быстро. Но тут появилась необходимость чуть отойти в сторону и началось. Оказалось, что документация покрывает только самые простые случаи использования, в свою очередь магия сокрывает внутреннию логику фреймворка, не давая возможности быстро разобратся по исходным кодам. Сообщество у фремворека есть и в интернете много ответов, но фреймворк так много и часто меняется, что эти ответы уже не актуальны и по большей части мешают процессу поиска информаци. В результате разработка привращается в ад.
        0
        Можете рассказать с каким проблемами вы столкнулись?
          0
          — Не очевидность кастомезации мепперов для API. И не очевидность того, что именно кастомезировать, описания требований я не нашел, поэтому все пришлось выяснять в процессе работы. Причем не всегда очевидно, что проблема в несоотвествие, обычно сначала сталкиваешься с проблемой, а потом уже выясняешь, что тут просто Ember ожидал другой формат ответа от API.
          — Не очевидно как передавать данные между разными элиментами приложения. Я так и не понял, как я могу иницировать запрос новых данных для одного контроллера из другого.
          — Как я уже написал, большая проблема с быстрым устаревание информации от сообщества. Чувствует большой дискомфорт, когда тебе не подходят ответы из топа гугла т.к. у тебя уже слишком новая версия эмбера.
            0
            1. Местами ember-data кривоват и с форматом json бывают проблемы, но я сталкивался всего 1 раз
            2. Я не совсем понял что вам нужно, Вы имеете ввиду вложенные контроллеры для айтемов?
            3. К сожалению, да
              0
              — Не очевидно как передавать данные между разными элиментами приложения. Я так и не понял, как я могу иницировать запрос новых данных для одного контроллера из другого.


              Сейчас переходят на компоненты, a-la React. Но в целом, конструкций вида this.controllerFor хватало. Опишите детальней пример, подумаю, как можно решить, потому что сам много раз бодался.
                0
                На второй вопрос: если вложенность, то делаете this.send('actionName') и ждете в более высокой роуте. Оттуда берете this.get('controller') и передаете в него информацию… В случае равнозначных контроллеров вам поможет cotrollerFor
                  0
                  cotrollerFor уже deprecated. Но это был не вопрос. Меня попросили привести примеры, я привел.
          +2
          В последнее время в вебе идет тенденция к «утончению» сервера и «утолщению» клиента. С каждым днем вакансий Full-stack разработчиков становится все больше, а чистого бэкенда все меньше

          • «утолщению» клиента идет довольно давно по известной причине, тонкий_клиент_браузер (браузеры) становится всё толще и код писать можно в формате RIA, только, конечно, не в терминологии вики, а в смысле, что можно внедрять фичи совершенно иного порядка, нежели обычное клацанье по контролам и прочий функционал порядка «это моя первая домашная страница».
          • а у чистого бэкенда, если вы не совсем курсе, последние 5-7 лет творятся такие вещи, что просто жуть — 3-4 крупных игрока (игры в компонентные фреймворки, или кто кого лучше заинтегрирует). То есть для фронта он конечно всё тоньше становится, но сам по себе утощается
          • Если мы говорим о каком-то конкретном языке\наборе инструментов, то (ИМХО) будущее специалиста зависит от его персональной должной активности в жизни сообщества этого языка\фреймворка и, конечно же, в больше степени, коллективной активности сообщества
          • Если мы говорим о специалисте в принципе, то не надо зацикливаться на языке\фреймворке. Простите за капитанство. Надо использовать инструменты, вернее, даже связку, которая лучше всего решает поставленную задачу


          + (ИМХО) и фронт и бэк в меру возможностей языков программирования развиваются в сторону SOA-инструментов. Грубо говоря, это когда любую маломальски полезную фичу можно оформить в виде готового подключаемого решения (S — сервис) и встроить в архитектуру (A — Architecture)

          А теперь внимание, какое это отношение имеет к Ember.js?

          Да очень простое. Вроде как для того, чтобы расширить\кастомизировать поведение приложения, приходится тщательно постучать в бубен (иногда стенкой в свой бубен). то есть он плохо соответствует этой тенденции развития в сторону SOA-инструментов. Поэтому, если я прав и если это не исправится, то очень скоро автор будет искать на кого-бы еще переучиться
            0
            Если не секрет, почему такой выбор из трех? Насколько я вижу, сейчас ReactJS набирает популярность, конкурирует с Angular'ом.
              0
              Метеор, как я говорил, отпал по причине того что хочу продолжать писать бэкенд на рельсах, а вот между ангуларом и эмбером выбор был сложный. Оба фреймворка хорошие, сообщества тоже. К тому же, я немного работал с Discourse и мне понравилось. В свое время, был в примерно такой же ситуации с Ruby и Python — больше понравился руби, начал с ним работать и теперь не хочу уходить.
              В React особо не вникал, но обязательно посмотрю.
                0
                Я тоже не хочу уходить с Рельс. Но хороший фронт тоже очень хочется. Я недавно написал первый апп с React & Rails. В итоге в приложении вместо slim/erb теперь jsx. React просто стал V в MVC рельс. Правда сам React ещё довольно молод и некоторые вещи приходится заново изобретать. Но, судя по темпам, оно скоро исправится. И надеюсь серверный рендеринг в геме допилят до вменяемого состояния.
                  +1
                  Я всё хочу спросить, как люди которые с React работают уживаются с этим кошмарным синтаксисом (JSX который)? Тем более после Slim.
                  Я как на него посмотрю, так сразу пропадает желание учить React. Хотя задумка вроде хорошая.
                    0
                    Я сначала тоже плевался и пока изучал — всё писал на чистом JS. Но как только переключился с коротких примеров на реальный апп, то очень быстро вернулся к JSX и сейчас у меня с ним в принципе harmony)
                      +2
                      Нет, так понятно что на JavaScript эти вьюхи писать невозможно при сколько-нибудь серьёзном объёме. Почему собственно вот это их «никаких шаблонов, только JavaScript» — полнейшая ерунда, JSX те же шаблоны, только уродливые (со смешиванием JS и HTML ещё и без явных разграничений).
                      Или я может один такой эстет и остальным это не принципиально?
                        +1
                        Вы не один) Нас даже не двое ;-) Вот ребята сделали тот же принцип, что у реакта (сравнение virtual-dom), но с обычными шаблонами http://www.ractivejs.org/
                          0
                          Ну вот да, это вроде по-человечески выглядит. Но насколько я понимаю, перспективы довольно туманные на фоне всеобщей любви к реакту? Ну то есть реакт-то понятно что теперь будут поддерживать, всё-таки это фейсбук, да и сообщество уже приличное набралось. А тут как-то сильно меньше уверенности.
                    0
                    >вместо slim/erb теперь jsx
                    >Правда сам React ещё довольно молод и некоторые вещи приходится заново изобретать
                    Если не менять erb на jsx, то можно использовать готовые решения на jQuery там где это нужно, а сложную фронтенд логику которую удобнее реализовывать с помощью MVC писать на react и подключать ее к erb. Большинству веб-приложений этого вполне достаточно, если, конечно, вы не пишете полноценное SPA. Чтобы все было быстро и современно – достаточно turbolinks с отдельными react компонентами. Все это крайне удобно дебажить и поддерживать, при этом никакие rails гемы переписывать под react не нужно.
                      0
                      SPA как раз и писал. Изначально поставил себе условие — без jQuery.
                    0
                    Derby не смотрели? Просто если речь о Метеоре зашла (который сколько я его помню, а этом минимум года два, «многообещающий но сырой»), то вроде Дерби намного приличнее смотрится (менее костыльный и не такой сырой), но сам пока его не пробовал.
                      0
                      Meteor вырвался вперед т.к. какое-то время назад получил $11.2M и пишет его команда, а не один человек как Derby.
                        0
                        Ну вот пишет-пишет и всё никак ничего приличного не напишет. Серверный рендеринг так вроде и не сделали по-человечески до сих пор. Хотя казалось бы очевидная вещь, если уж код изоморфный. На Дерби это есть чуть ли не с самого начала.
                  +1
                  Отлично написано, отдельный плюс за четкие схемы и подробное описание. Жду следующей част.
                    0
                    Уже давненько работаю в EmberJS… В самом начале плевался и ругался на него, а после, когда вник и разобрался, то понял, что штука замечательная: все довольно быстро и удобно.
                      0
                      Вроде слышал что начиная с определённого уровня сложности приложения приходится «бороться» с фреймворком. Ну то есть чтобы вот здесь сделать не так, а немного по-другому, а фреймворк не даёт, он лучше знает. Нет такого?
                        0
                        Тут есть определенные нюансы, но решить их можно с помощью Ember
                      0
                      Клиент жирнеет только в некоторых областях. Если вы пишете публичный сайт, который должен хорошо индексироваться, и хотите максимальной скорости отображения то шаблонизация на сервере и тонкий клиент никуда не уйдут.
                      Клиент пожирнел, в интранетах или в интернет сервисах которые и раньше с трудом можно было назвать сайтами.
                        0
                        выбор фреймворка человека, который пришел с серверной разработки:
                        Java -> Angular
                        Ruby -> Ember
                        .NET -> Knockout

                        я не говорю что это 100%, но сами понаблюдайте на своем примере и примере коллег с других проектов (которые конечно могут влиять на выбор фреймворка)
                          0
                          Вообще похоже, правда у нас два проекта java + ember и ruby + ember.
                            0
                            Да, действительно. Тенденция прослеживается в «Разбор полетов» все любят Angular.

                          Only users with full accounts can post comments. Log in, please.