- Bounded contexts (Dependency management)
- Concerns
- Observers
- Domain Events
- Datatypes
- Service Layer
- Serialization (store, hstore, serialize)
- NoActiveRecord
-
-
Save niquola/5967445 to your computer and use it in GitHub Desktop.
class PendingOrdersService | |
def initialize(visit, user) # service context | |
@visit, @user = visit, user | |
end | |
## Queries | |
def pending_orders | |
... | |
end | |
def ordering_providers | |
end | |
## Actions | |
def build | |
... | |
end | |
def add_to_pending | |
end | |
def sign_pendings | |
end | |
def cancel | |
end | |
end |
class SignPendingOrdersService | |
def initialize(visit, user) # service context | |
@visit, @user = visit, user | |
end | |
def call # or execute | |
Order.for_visit(visit).pendings.each do |order| | |
order.activate! | |
OrderTemplate.find_or_create_template_for_order_and_record_template_usage!(order) | |
end | |
end | |
end |
op = OrderingSession.new(visit, user) | |
op.ordering_providers | |
order = op.build_order(attrs) | |
order = op.orders.create(attrs) | |
op.sign! | |
op.cancel | |
order = op.orders.find(params[:order_id]) | |
order.destroy | |
class OrderSession | |
class OrderProxy | |
attr_reader :order_session | |
delegates * to: :_order | |
def save | |
puts 'here' | |
_order.save | |
end | |
def default_ordering_provider | |
order_session.user.role?(:nurse) ? visit.attending_doctor : order_session.user | |
end | |
end | |
def build(attrs) | |
OrderProxy.new(Order.build(attrs)) | |
end | |
def orders | |
Order.pending.for_visit(visit).map { |o| OrderProxy.new(self, o) } | |
end | |
def sign! | |
orders.each do |o| | |
o.activate! | |
create_document(o) | |
remember_template | |
end | |
end | |
end |
- They are used for integration code which does not fit in any model.
- They are used for integrating different context of application.
- Separate USE CASE (application) LOGIC from DOMAIN LOGIC
which performs only one action (much like DCI context)
Single-action service: USED IN POINT OF DIFFERENT CONTEXT INTEGRATION OR USE-CASE SPECIFIC CALCULATIONS OR LOGIC
- http://mikepackdev.com/blog_posts/24-the-right-way-to-code-dci-in-ruby
- http://railscasts.com/episodes/398-service-objects
- http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
Incapsulates anything from Rails controller under procedural API.
Business Controller: THE LAYER BETWEEN DOMAIN AND RAILS, ALLOWS TO EXTEND EVERY STEP OF USE-CASE WITH CUSTOM LOGIC.
Implement object-oriented API for service instead of procedural. You can use something like OrderProxy to add custom logic on model create/update/etc.
Resource-based: IF YOU HAVE INTEGRATION OR USE-CASE LOGIC IN CONTROLLER YOU REPLACE MODEL WITH RESOURCE SERVICE.
Other variants of application-wide integration is Observers or Pub/Sub pattern (Events). But they cannot return value, so they are useful only as post-action callbacks.
| |
- use only | - implement 'stub' | + override only when needed | actions for uniformity| actions you need | | | |
- unit-test | + integration test | + integration test | (as blackbox) | (repends on impl) | |
- simplest | + simple | - hard to implement | | (a lot of magic) | |
- single resp | +- use-case respons | +- use-case rsponsibility | |
- strong api | - variable api | +- model-like api | |
- a lot of | +- 1 serv for 1 use- | +- same as business contrl different en| case, but may be fat | | |
- can be easily - hard to reuse and | - same as business contrl reused and | because of single-purpose combined | impl. | | |
- cannot be | + can be used in prot,| +- can be used for proto, used for proto| with const API | but not easy | |
- rich model | - can lead to anemic | + rich model | model | | |