Mining gems in your existing codebase

Post on 08-Aug-2015

135 views 0 download

Tags:

Transcript of Mining gems in your existing codebase

Mining gems in your existing codebase

@sanderhahn amsterdam ruby meetup 17th Dec 2014

Agenda• Why extract gems?

• Prevent Rails apps to grow into monoliths

• How to design more modular apps?

• Railties, plugins, engines and mountables

• Ready for microservices?

• Just a perspective, open for discussion and your milage may vary

How Rails evolves

• Rails is a collection of separate gems living inside a single git repository (synchronised release planning and versions)

• Deprecation is done by including and extracting functionality into separate gems to allow managing technical debt (optional use of new and legacy gems)

Evolution by inclusion and extraction

• attr_accessible moved into protected_attributes gem, replaced by strong_parameters gem

• responds_with into responders gem

• cache_digests gem

• asset pipeline into sprockets-rails gem

• active_resource gem

Rails apps are structured by type

• app/assets

• app/controllers

• app/models

• app/views

• config/routes.rb

• db/migrate

Monolithic apps

• Rails development is very fast in greenfield projects but can become slower as your application and team grows

• Tests might require large fixtures of unrelated data and can take a long time to run

Engines enable apps to be structured by function

• Website Content

• Newsletter Subscription

• Lead Generation

• Webshop

• Public API

Advantages• Apps are build from logical separate modules

with explicit boundaries

• Distribute responsibility of code and work in a team

• Code reuse in client projects is possible

• Tests are more isolated and run faster

• Technical dept is easier to manage

Guiding principles

• Loosely coupled system is one in which each of its components has little or no knowledge of the definitions of other separate components

• High cohesion means to keep similar and related things together which share the same responsibility or goal

How to dissect apps into modular gems

• Railties (initialization)

• Plugins (extend Rails functionality)

• Engines (app composition)

• Mountable's (isolated namespace and route)

Foundation of Rails# rails/railtie.rb class Railtie

# rails/engine.rbclass Engine < Railtie

# rails/application.rb class Application < Engine

# config/application.rbclass Application < Rails::Application

Railtie provides several hooks to extend Rails and/or modify

the initialization process

Rails components are Railties

ActionMailer example

Plugin is an extension or a modification of the core

framework

Plugin structure$ rails plugin new gems/myplugin

Gem dependencies

Plugin config with Railtie

Engine is a miniature application that provides functionality to its

host application

Engine structure$ rails plugin new gems/myengine --full

Rails generate/destroy are available inside an engine

$ cd gems/myengine

$ rails generate scaffold user name:string

$ cd ../..

# add dependency in Gemfile

$ rake myengine:install:migrations

Mountable is a namespace-isolated engine

Mountable structure

$ rails plugin new gems/mymountable --mountable

Rails inside a mountable

$ cd gems/mymountable

$ rails generate scaffold post user:references title:string

$ cd ../..

# add dependency in Gemfile

$ rake mymountable:install:migrations

Engine vs mountables

Cross engine url_helpers

Testing an engine• At application runtime all engines are available

• Integration testing is done by creating a dummy app inside the test dir

• Other engines are only available if specified as a dependency

• Fake models and migrations can be created in the dummy app on engine boundaries

Dummy app for integration test in the devise gem

Example: Tolk gem is a Rails engine for translating your app to other languages

Tolk structure

Tolk generator

Thor and Generator actions

Breaking the Monolith @ Soundcloud

We decided to move towards what is now known as a microservices architecture. In this style, engineers separate domain logic into very small components. These components expose a well-defined API, and implement a Bounded Context — including its persistence layer and any other infrastructure needs. … In the end, the team decided to use Rails' features of engines to create an Internal API that is available only within our private network.

http://www.slideshare.net/pcalcado/from-a-monolithic-ruby-on-rails-app-to-the-jvm https://developers.soundcloud.com/blog/building-products-at-soundcloud-part-1-dealing-with-the-monolith https://developers.soundcloud.com/blog/building-products-at-soundcloud-part-2-breaking-the-monolith https://developers.soundcloud.com/blog/building-products-at-soundcloud-part-3-microservices-in-scala-and-finagle

Engines vs microservicesMicroservice architectural style: designing software applications as suites of independently deployable services

http://martinfowler.com/articles/microservices.html

Bounded Context helps guiding engine design

Domain-driven design (DDD) deals with large models by dividing them into different Bounded Contexts and being explicit about their interrelationships

http://martinfowler.com/bliki/BoundedContext.html

Thank you!