Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- SOA without the tears (A pragmatic alternative with embedded Rails engines) - Jon Wilkinson, Anthony Zacharakis - Lumosity
- - Overview
- - failed attempts and why
- - what are embedded engines?
- - when can I use embedded engines?
- - Lumosity have:
- - 15 devs
- - 45mm users
- - Application since 2007
- - 28k commits, 160 new commits/week
- - a 'large' application
- - Large app problems
- - slow
- - loading gems and files
- - build takes 1 hr 7 mins 13 secs (358 tests 2 pending) w/ 24 cores on ruby-1.9.3-p327 [from screen-shot]
- - complicated
- - end up with a lot of god models
- - data flow complexity
- - fragile
- - adding new features breaks existing features
- - Solutions
- - SOA (service oriented architecture)
- - Basically breaking down your App into several Apps which communicate w/ well defined APIs and explicitly specified dependencies
- - A /lot/ of work to break down an existing application into an SOA model
- - new bugs (dealing with time-outs)
- - dealing with lots of legacy (*cruft*)
- - dev friction
- - difficult to test
- - difficult to secure
- - A compromise
- - broke code out into modules
- - trouble
- - discourage code independence
- - engines!
- - Engines
- - miniature applications which provide functionality to the host applications
- - engines are isolated and unable to reach into host state
- - engine construction is easy ``` rails plugin new <name> --mountable ```
- - a trick
- - to embed engines in your repo:
- - use #local_engine in the GemSpec ``` def local_engine(name); gem name, path: "engines/#{name}"; end ```
- - when extracting Tables, prefix tables with the engine name (to prevent conflicts)
- - associations, don't use associations because they encourage tight coupling
- - paths, ( /login -> /<engine>/login ) they're mounted in a namespace
- - seems complicated
- - engine specific config
- - such as: configuration options, route helpers, feature flags, AB tests, external model data, callbacks, hooks
- - make an initialiser and adjust it to do your engine specific config
- ```
- # in config/initializers/user_auth.rb
- class UserAuth::LoginsController
- def show
- @allow_facebook = Feature.enabled?(:facebook)
- end
- end
- ```
- - refactor engine to depend on config
- - dependencies
- - cross-engine and host dependency is evil, do not depend on the host app or other engines -- you will regret it
- - example:
- ```
- Dearest <%= first_name_or_whatever %>,
- We're <%-= deeply_touching_sentiment %> that you joined and thought you should check this out:
- <%= image_tag(purchase_driving_gaph_path %>
- Warm regards,
- Lumosity
- ```
- - If you want to CDN that image, you add:
- ```
- UserAuth.cdnize = ->(path) do # lambda notation
- UrlMethods.cdnize(path)
- end
- ```
- - in the engine:
- ```
- cdnized_url = UserAuth.cdnize(<url>)
- ```
- - avoid main app knowledge of engine internals
- - isolate data by putting all main app accesses into a module which explicitly conveys the API
- - testing
- - use a dummy application.. you don't need to load all your dependencies of your main app
- - dummy apps expose hidden dependencies (ex. translation error, the engine was expecting translations which only lived in the main app)
- - faster feedback loops
- - faster tests better tests
- - do not forget about your integration tests (you'll need them since you've got inter-engine dependencies in terms of data flow)
- - When should I use engines
- - old applications with lots of functions? yes.
- - large teams? yes. more independence.
- - Lumosity have over a dozen engines in production today inside their app
- - benefits
- - lightening fast specs
- - peace of mind
- - self describing
- - Thanks
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement