Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Корпоративное приложение на Rails

530 views

Published on

Проблемы, которые возникают в Rails приложении при создании корпоративного приложения.

Published in: Software
  • Be the first to comment

Корпоративное приложение на Rails

  1. 1. Корпоративное приложение на Rails. Отчет после года разработки Андрей Колешко @ka8725
  2. 2. Что представляет из себя наше приложение • Полно бизнес логики • Работа с деньгами клиентов • Общение со сторонними системами • Очереди обработки данных (sidekiq) • Асинхронность • Поддержка плагинов через Rails engines • Звездолет
  3. 3. Приблизительное состояние кода в проекте
  4. 4. Быть или не быть? • Посмотрим с какими проблемами мы столкнулись и как с ними боролись • Какие проблемы не решены • Попробуем сделать выводы, можно ли использовать Rails в коммерческих приложениях
  5. 5. Модульность • Ruby modules • Rails engines
  6. 6. Ruby modules • Многие гемы просто не готовы к тому, что мы будем использовать Ruby модули • DataGrid - не было возможности изменить шаблоны для client и admin области • Draper - для работы декоратора в пространстве имен приходится писать магические строчки • InheritedResources - поиск ресурса (AR модельки) в модуле не был реализован • Rails - polymorphic routes генерировали неправильные helper-методы
  7. 7. Rails Engines • Нельзя использовать разные версии gems в ядре и плагине • В Ruby нет интерфейсов. Нельзя заставить плагины реализовать все методы, которые нам нужны • Тестирование Rails Engines в контексте ядра - болезненный процесс • rake railties:install:migrations постоянно генерирует новые файлы • Установленный Rails Engine может поломать все приложение. У него есть доступ ко всему
  8. 8. Имеем дело со всеми известными проблемами модульного приложения
  9. 9. Как мы преодолеваем проблемы сейчас • Pull request’ы в гемы, которые не готовы к использованию Ruby модулей • Для плагинов предоставляем миксины • Общение с плагинами стараемся выстраивать через самописный Pub-Sub, основанный на ActiveSupport::Notifications- • Тестируются плагины вручную- • Собственный регистратор плагинов
  10. 10. Пример Pub-Sub # Core Publisher.broadcast_event('user.created', {user_id: 1}) ! # Plugin Subscriber.subscribe('user.created') do |event| payload = event.payload puts payload[:user_id] end http://goo.gl/QJxujy
  11. 11. Особенности нашего Pub- Sub • Однопоточный • Нет обратной связи. Сообщения однонаправленные
  12. 12. Собственный регистратор плагинов • Дает простую установку копированием плагина в нужную папку • Контролируемый процесс подключения плагина к системе • Плагин - Rails engine
  13. 13. Преимущества Rails engines как модулей • В плагинах можно изменить все. View, Routes, Controllers, Models, Helpers… • Быстро работает (нет сторонних вызовов)
  14. 14. ActiveRecord • Избегаем nested_attributes • Используем FormObjects, ServiceObjects, QueryObjects, PolicyObjects • В моделе остается только отображение данных и самые необходимые валидации, ассоциации • Избегаем Observers и Callbacks
  15. 15. Исключение для использования callbacks • Отправка сообщения в очередь для фоновой обработки • Не изменяет состояние объектов
  16. 16. Observers • Правила использования не отличаются от callbacks • Ведут к более запутанному коду чем callbacks • Лучше никогда не использовать
  17. 17. Завязались окончательно?
  18. 18. Возможноcть развязать узлы в тестах ! • Отключаем все колбэки в моделях • Включаем колбэки в тестах в тех местах, где их вызов необходим • Не используйте этот подход в новых приложениях!
  19. 19. Возможность оставить тесты рабочими class ActiveRecord::Base cattr_accessor :skip_callbacks- end ! class User < ActiveRecord::Base after_create :send_invitation, unless: :skip_callbacks def send_invitation puts 'hello' end end ! ActiveRecord::Base.skip_callbacks = true User.create # => ActiveRecord::Base.skip_callbacks = false User.create # => 'hello'
  20. 20. Слой View • Проблема с длинными именами helper-методов • Использование instance переменных (@var) во view • Рендеринг таблиц • fields_for и nested_attributes • Фарш AngularJS
  21. 21. Длинные имена helper- методов plugin_exchange_client_account_application_contact_ contact_distribution_group_path(parent.account, parent.core_application, parent, resource) ! Всего 141 символ!
  22. 22. Решение # Controllers class SomeController < ApplicationController helper_method :submit_path helper_method :cancel_path ! private ! def submit_path any_size_of_helper_method_you_want_submit_path( arg1, arg2, … ) end ! def cancel_path any_size_of_helper_method_you_want_cancel_path( arg1, arg2, … ) end ! end
  23. 23. Решение # Views ! = form_tag submit_path do = link_to 'Cancel', cancel_path
  24. 24. Преимущества решения • “Чистый”, читабельный и более надежный код во view • HAML вам сважет спасибо ! PS. Не используйте HAML! Есть более удачный шаблонизатор - SLIM.
  25. 25. Helper-методы вместо @var • Ошибка рендеринга более адекватная (undefined method my_helper_method вместо undefined_method “…” for nil class)
  26. 26. Рендеринг таблиц • DataGrid- • Сортировка и фильтрация из коробки • Беспроблемная интеграция с пагинаторами и полнотектовыми движками (через свои scopes) • Возможность изменять шаблоны таблицы • view занимают всего 3 (!!!) строчки кода • и другое - https://github.com/bogdan/datagrid
  27. 27. fields_for и nested_attributes • В FormObjects сложно обрабатывать магические хеши nested_attributes • В большинстве случаев необходимо использовать свой primary key для поиска записи на обновление в базе. А не id, который зашит в rails хардкором • Огромные имена переменных ассоциаций
  28. 28. fields_for и nested_attributes - form_object.locations.each do |location| = f.fields_for 'locations[]', location, include_id: false, index: nil do |ff| # include_id: false - предотвращает генерацию hidden field c id, т.к. нас это не устраивает # index: nil - не включать index в название сгенерированного аттрибута
  29. 29. Преимущества данного подхода • Имена параметров чистые и понятные • Возможность передавать на сервер свой primary ключ для поиска модели на обновление • Проще обработка в FormObjects
  30. 30. Фарш AngularJS • Т.к. состояние объектов хранится на сервере необходимо вручную вызывать ng-init • В каждый input необходимо передать ng-model атрибут • Если в ng-init забыт атрибут, который связан с ng-model, то получим некорректное отображение объекта на форме • Что делать при успешном сохранении формы? Reload страницы? - Теряем flash сообщения
  31. 31. Разработка на Rails быстрая? • Только для небольших приложений • Огромное количество кода препятствует быстрой разработке
  32. 32. Rails way Enterprise way
  33. 33. Выводы • Rails отлично подходит для создания прототипов- • К модульности и огромным приложениям Rails не готов • В сложных приложениях приходится отказываться от многих магических палочек Rails- • Это ведет к увелечению собственного кода • Код требует ухода. Знание шаблонов проектирования, принципов проектирования классов (SOLID) здесь просто необходимо
  34. 34. Что в Ruby хорошо? • Писать DSL • Сам язык очень выразительный • Код приятно писать и читать • И на этом все :(
  35. 35. Решились писать Enterprise на Rails? • Нужен ли Вам Rails? Может, достаточно взять Sinatra + Grape, если у вас будет SPA (Single Page Application)? • Тщательно обрабатывайте требования. Выясняйте Use Cases- • На основании UseCases стройте доменную модель (набор классов и их взаимодействия). • Не привязывайтесь к ActiveRecord. ActiveRecord - только для представления данных! • Тщательно выбирайте гемы. Подумайте 100500 раз прежде чем выбрать InheritedResources, например. • Следуйте принципам SOLID, не нарушайте закон Деметры
  36. 36. Литература 1. http://goo.gl/GyqjXg - 7 steps to get started with Clean Architecture in Ruby 2. http://goo.gl/g0VA1 - 7 Patterns to Refactor Fat ActiveRecord Models 3. http://goo.gl/lz1fEX - Ruby Midwest 2011 - Keynote: Architecture the Lost Years by Robert Martin 4. http://goo.gl/MP6L7Z - High-Low Testing 5. http://goo.gl/aI3kdc - Growing Rails Applications in Practice 6. http://goo.gl/9KsmM - Принципы проектирования классов (S.O.L.I.D.)
  37. 37. На правах рекламы ! Основы Rake Простые примеры применения в реальном мире Сравнение с конкурентом - Thor
  38. 38. Вопросы? Андрей Колешко @ka8725- ka8725@gmail.com

×