Как стать автором
Обновить

Пересекая границы: случай с рельсами

Время на прочтение11 мин
Количество просмотров781
Автор оригинала: Bruce Tate
Разработка на Ruby on Rails различается по фундаментальным позициям от разработки на Java. В этой статье Брюс Тейт описывает основные различия, которые он обнаружил при использовании Rails для разработки сложных, масштабируемых Web-сайтов с нуля.

Разработчики на рельсах часто смотрят на своих коллег — любителей кофе, как на остатки прошлого. А приверженцы Java часто описывают Ruby on Rails как игрушку, которой не место в каком-либо серьезном проекте по разработке ПО. Как консультант, интенсивно проработавший с обеими технологиями, я знаю, что правда лежит где-то посередине. Поскольку данная серия «Пересекая границы» заканчивается, я хотел бы сделать еще одно сравнение. Вместо того, чтобы рассматривать определенный язык или технологию, я сфокусируюсь на своем текущем проекте и сравню его с Java-проектами, над которыми я работал в прошлом. (Пользуясь случаем, направлю вас к предыдущим статьям серии «Пересекая границы», которые более подробно описывают рассматриваемые здесь темы). Это статья в первую очередь должна дать понять вам какие недостатки и потенциальные преимущества имеются при использованием Rails для разработки Web-приложений, основанных на базах данных.

Бизнес-задача


Ни Ruby on Rails, ни Java не являются единственно правильными решениями для какой бы то ни было проблемы. Чтобы увеличить вероятность успеха, вам надо долго и досконально рассмотреть вашу бизнес-задачу, понять окружение и знать вашу команду. Только после этого вы можете выбрать хороший язык для решения вашей задачи.
В прошлом году Arvando Systems наняла меня в качестве руководителя команды, которая должна была разработать ChangingThePresent.org, новый продукт, который бы помог объединить доноров и некоммерческие организации вместе. Подобно многим интернет-компаниям, мы продаём понятные продукты, которые наши покупатели покупают. Но в отличие от других компаний, «продукты» представляют собой возможности(или подарки), такие как оплата часа работы исследователя раковых заболеваний за 50$, помощь слепому человеку за 30$ или защита акра векового леса в течении месяца за $20.
У нас были два основных вызова: амбициозный план и длинносрочная сложность (сложность на всем протяжении разработки проекта).
Мы начали разработку в сентябре и мы должны были закончить разработку до ноября, чтобы получить хорошую прибыль за рождественские каникулы.(На самом деле мы задержались на две недели). Мы знали, что решение, основанное на Java займет от 6 до 18 месяцев. Продуктивность имела очень большое значение. Java-решение не удовлетворяло этому требованию.

Рассматривая вызовы брошенные нам, мы знали, что сможем привлечь трафик порядка миллиона заходов в день. Мы должны были справляться с сотнями тысяч хитов в день, чтобы быть успешными, поэтому масштабируемость имела большое значение. Это указывало на использование Java.

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

Я верил, что язык Ruby — с его возможностями как языка высокого уровня, — и Rails — со сниженными потребностями в конфигурировании и более простой, интегрированной моделью программирования — мог бы лучше масштабироваться с точки зрения сложности.

Но время и масштабируемость работали против нас, остальные факторы работали на нас. Мы имели абсолютно чистое состояние: мы могли выбрать любую технологию, любую команду, которую мы хотели. Мы могли определять проект, культуру, и полный набор технологий. Вобщем, мы имели полную свободу выбора.

Java превосходный язык общего назначения. Он всегда ориентируются на новые возможности, такие как встроенные системы и мобильные устройства. Java также преуспевает в сочетании различных требований. Он высокопроизводителен, популярен и хорошо поддерживается на рынке. Но, как вы видели в этой серии, Java необязательно лучший выбор для разрабоки Web приложений, основанных на базах данных, с нуля (см. статью «Web development strategies in dynamically typed languages»).

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

Как только мы приняли решение, мы быстро рекрутировали талантливого разработчика для проекта. Мы также обнаружили, что наша продуктивность была фантастической — даже больше, чем мы ожидали. У нас были некоторые проблемы сначала со стабильностью, поэтому мы удвоили наши усилия по тестированию (см. статьи «Testing in integrated frameworks, Part 1» и часть 2). С момента удвоения мы повысили нашу стабильность невообразимо.

Философия


Каждый разработчик фреймворка работает с набором предположений, которые создают философию фреймворка. Изучите как жить с ограничениями данной философии и вы — счастливый программист. Боритесь с ними, и вы почувствует себя сокрушенным. Rails и Java имеют совершенно разные философии.

Rails — интегрированный фреймворк, который интенсивно использует динамическую природу Ruby (см. статью «What's the secret sauce in Ruby on Rails?»). Rails разработчики усиливают свойства фреймворка с целью повышения продуктивности, а не вводят новые средства для поддержки средств разработки, и зачастую принимают упрощенный взгляд на веб-архитектуру, как вы видели в предыдущих статьях этой серии. Java-разработчики должны часто соединять вместе куски своего окружения, выбирая независимо систему хранения объектов (persistence), web-систему и интегрируя их. Они часто полагаются на средства разработки, чтобы упростить ключевые задачи. Web-архитектура судя по всему сложнее с точки зрения разработки.

Полная интеграция


Java стремится решить одну маленькую проблему, такую как персистенс или организация видов, а Rails — интегрированная среда.

Достоинством для разработчиков на Rails является то, что им не надо решать проблему интеграции многих различающихся по сути фреймворков.

Большинство разработчиков Hibernate попали в ловушку преждевременно разрывая связь с Java web-фреймворками. Rails view фреймворки строятся с нуля с расчетом на интеграцию с ActiveRecord, фреймворком хранения объектов Rails. Вы испытаете одинаковые ощущения работая с Rails фреймворки для Web сервисов, конфигурациями, и подключаемыми модулями. Java поддерживает множество существенно различающихся по сути фреймворков, с различными подходами к интеграции всех этих вещей.

Достоинство Java разработчиков — выбор. Если вам нужно построить фреймворк с нуля, вы можете рассмотреть решение основанное на SQL для интеграции с БД такое, как iBATIS или один из многих JDBC-based фреймворков-оберток для Java. Если, наоборот, вы начинаете со своей схемой БД, вы можете рассмотреть ORM-фреймворки такие как Hibernate. Если вы используете Rails у вас есть единственный основной выбор — ActiveRecord. Это значит, что Java-фреймворк, предоставляя больший выбор, иногда предоставляет лучшее решение для интеграции проектов. Но поскольку мы разрабатывали проект с чистого листа, выбор не был большой проблемой.

Динамический язык


Следующая основная составляющая философии Rails — динамический язык программирования (см. статью «Typing strategies beyond the Java model»). Java средства стремятся эффективно использовать дополнительную информацию, предоставляемую моделью типизации Java. Средства могут обнаруживать ошибки и эффективно реструктурировать или рефакторить код. Rails также эффективно комбинирует преимущества языка программирования. Ruby — идеальный язык для создания языков, специфичных для предметной области (domain-specific languages — DSL) (см. статью «Domain-specific languages in Active Record and Java programming»). Rails интенсивно принуждает использовать DSL для всего: от создания отношений между объектами модели до задания произвольных компонент таких, как конечные автоматы и загружаемые на сервер изображения. Динамические языки часто более понятны, поэтому проекты на Rails намного более кратки чем их Java аналоги, позволяя пользователям писать и код, и конфигурации более ясно. В ChangingThePresent.org мы заметили, что наши топ-программисты могут быть более продуктивны и нам не надо нанимать программистов с большим опытом. Я счастлив от этого.

Типичный Java программист религиозно привержен своей IDE и имеет на то хорошую причину. IDE предоставляет ему подсказки кода (code completion),
устраняет типичные ошибки и предоставляет инкрементную компиляцию с целью ускорения цикла кодирования, компилирования, размещения и тестирования. В последние годы, среды разработки начали использовать еще больше информации, предоставляемой циклом компиляции и статической типизацией. IDE сейчас редактируют абстрактные синтаксические деревья вместо или в дополнение к текстовому представлению кода. Эта стратегия поволяет создавать мощные средства рефакторинга, которые намного более сложно получить используя те же методы для динамически типизированных языков.

Статическая типизация позволяет получать хорошие средства разработки, но оно имеет и недостатки. Статическая типизация требует компилятора, и шаг компиляции может абсолютно разрушить продуктивность. Используя Rails, я могу изменить строчку кода и перезагрузить браузер, сразу же видя результат изменений. В противоположность Java программистам, большинство Ruby программистов используют только хороший текстовый редактор. TextMate, наиболее популярный редатор для Ruby on Rails, подсвечивает синтаксис, дополняет код и имеет хорошую поддержку шаблонов для часто используемых конструкций. И редактор более чем достаточен для написания простых Ruby скриптов, которые лежат в основе Rails. Вместо полноценного дебуггера, я использую скрипт breakpointer, который может остановить указанное приложение и отослать меня к Ruby интерпретатору, где я могу вызывать методы, просматривать значения переменных и даже модифицировать код перед тем как продолжу выполнение.

Простая архитектура


Типичная Java архитектура Web-приложения имеет уровень объектов предметной области (domain objects), объектов доступа к данным(data access objects), фасадный уровень, предоставляющий API уровня бизнеса, уровень конроллера и уровень вида. Эта архитектура слегка сложнее чем классическая архитектура модель-вид-конроллер, которая была впервые использована в языке Smalltalk. Наоборот, RoR использует один уровень модели, используя паттерн ActiveRecord, уровень контроллера и уровень вида. Мы любим подход Rails. Он более понятен и оставляет меньше места для появления дополнительной сложности и ошибок.

Договоренности (соглашения) вместо конфигурации


Java-фреймворки часто используют XML-конфигурации, в то время как рельсы в основном используют договоренности, чтобы избежать конфигурации там, где это только возможно. Там где программист должен что-то сконфигурировать, Rails полагается на Ruby, часто в форме DSL для конфигурирования. Для разработки с нуля, я нахожу что договоренности вместо конфигураций имеют смысл. Эта стратегия сокращает мне много строк кода и упрощает код, которыя я должен написать. Мы прикинули, что у нас используетя 1/10 конфигурирования, которое пришлось бы делать на Java. Мы иногда теряем в гибкости, но не настолько, чтобы этот недостаток превзошел приобретения.

Подводя итоги, философия рельс-фреймворка отлично подходит для решения задачи создания changingthepresent.org. Интегрированный стек позволяет мне получить большую функциональность от фреймворка без необходимости делать ненужную интеграцию самому. Философия договоренностей вместо конфигурации сохраняет мне время. Динамический язык дает моим бывалым разработчикам больше мощи и гибкости, одновременно позволяя выражать более продвинутые идеи при меньшем количестве кода. Фреймворк согласуется со способностями моей команды также как и с бизнес-задачей, которую мы решаем.

Персистенс


Наиболее популярные фреймворки хранения для Java и Ruby иллюстрируют различие между ними намного лучше, чем все остальные возможности. Java разработчики обычно используют Hibernate. С Hibernate вы берёте существующую модель и существующую схему и задаете соответствие между ними используя аннотации или XML. Hibernate классы являются POJO, где каждый объект порожден одним общим базовым классом. Большинство конфигурирования осуществляется явно, используя аннотации, XML или комбинацию обоих методов.

ActiveRecord, напротив, является фреймворком-оболочкой, а это значит, что каждый класс оборачивается вокруг существующего класса (см. «Exploring Active Record»). ActiveRecord автоматически добавляет фичи в объекты модели, основываясь на содержании ассоциированной таблицы, таком как атрибуты каждого столбца в таблице. Все классы наследуют от общего базового класса. ActiveRecord в основном конфигурируется за счет общепринятых соглашений. Например:
  • ActiveRecord находит таблицу основываясь на имени класса, которое указывается в множественном числе
  • Имя первичного ключа — id.
  • Порядок сортировки списков опрделяется полем, названным position.

ORM лучшее решение, когда у вас есть готовая схема, возможно уже разработанная с учетом объектной модели. Но когда вы разрабатываете схему БД явно для вашего приложения, вам часто не нужен фреймворк ORM. Мы рассматриваем ActiveRecord как потрясающее преимущество для нас. Мы можем воспользоваться реляционной БД, используя SQL по необходимости, или оставаться выше SQL, когда это удобно.

Миграции


Рельсомиграции (Rails migrations) позволяет нам указывать отличия между двумя версиями схемы и данными, которые они содержат, в коде (см. «Rails migrations»). Каждая миграция именуется и нумеруется. Я могу переходить от версии к версии схемы в любой момент времени.

Миграции имеют некоторые особые преимущества, позволяя нам:
  • восстанавливать более старую версию схемы, когда мы убираем плохой код
  • задавать схему в коде вместо SQL, что более удобно для нас
  • быть независимыми от БД в большинстве случаев

Но миграции имеют ограничения. Если два разработчика создают миграции в одно и то же время, номера могут перепутаться и мы должны вмешаться вручную. Мы минимизируем эти проблемы эффективным общением: члены команды говорят когда они строят новую модель, требующую миграцию. Но эта модель как правило, зависит от небольшого числа разработчиков или затрагивает небольшую части миграции.
ActiveRecord имеет и другие недостатки, некоторые из них сделаны намеренно. Основатели Rails верят что ограничения (constraints) и композиции задаются в приложении, а не в базе данных и это вызывает побочный эффект. ActiveRecord не очень хорошо использует виды: процесс создания, который клонирует схему, копирует тестовые данные и запускает тесты не копирует их правильно.
ActiveRecord также имеет сложности в некоторых случаях с ссылочной целостностью (referential integrity), поскольку некоторые типы ассоциаций могут использовать более одной таблицы БД. Интенсивная загрузка сложных моделей очень сложна и часто требует SQL, когда несколько строк должны быть объединены. Наследование ограничено: с ActiveRecord меня вынуждают использовать стратегию ассоциации (mapping) названную singe table inheritence, что не всегда оптимально.

Все стратегии хранения объектов являются клубком компромиссов. Я верю, что ActveRecord поражает эффективным набором компромиссов, правда грешит с точки зрения простоты. Таким образом, ActiveRecord плюс миграции — большой плюс для нас. Мы можем создавать наше решение быстро, и мы имеем достаточный доступ к SQL для повышения производительности когда нужно. Но было бы здоров использовать Rails с проектами имеющими готовые схемы, с которыми ActiveRecord не всегда выигрывает. Альтернативные модели хранения развиваются, включая RBatis — порт iBATIS Java фреймворк (см. ресурсы). Но слишком рано говорить насколько эффективен будет RBatis.

Заключение


Для моей команды и моей ситуации, Ruby on rails оказался дико эффективен. Я пока не знаю насколько хорошо проект масштабируется, поскольку мы живет только три месяца. Мы только сейчас получили солидный прирост трафика. Но мы знаем о продуктивности.
Я знаю, что команда прошла по пути, требующем меньшего бюджета в отличие от конкурирующих лавочек, предлагающих Java-решения. Я также удовлетворен нашей продуктивностью.

В серии «Пересекая границы» я познакомил вас с языками и решениями вне области решений Java. Программисты, в конце концов, ремесленники. Набор каждого опытного ремесленника должен содержать широкий спектр инструментов, которые подходят для каждой ситуации. Кроме средств, перспектива которую вы увидели, предлагает новые идеи, которые вы можете использовать. Даже сейчас, разработчики фреймворков применяют техники из Seaside, Rails и даже из JavaScript в Java фреймворках. Ищите шанс сделать то же самое, чтобы пересечь границы.

Об авторе


Это - Брюс ТейтBruce Tate — отец, горный байкер и кайякер из Остина, штат Техас. Директор по технологиям(CTO) компании WellGood LLC и главный архитектор ChangingThePresent.org. Он также автор трех бестселлеров по Java, включающих Jolt winner Better, Faster, Lighter Java. Недавно он выпустил From Java to Ruby on Rails: Up and Running. Он проработал 13 лет в IBM и позже сформировал консалтинговую фирму RapidRed, специализирующуюся на легких стратегиях разработки и архитектурах основанных на Ruby и Ruby on Rails.
Теги:
Хабы:
+3
Комментарии14

Публикации

Истории

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн