Example class FooOperation def self.execute!(baz_id) ActiveRecord::Base.transaction do Foo.create! BarOperation.execute!(baz_id) end end end class BarOperation def self.execute!(baz_id) Bar.create! # more complicated logics... end end
fetch data from other services class FooOperation QUERY = "query(bazId: $ID!) { baz(id: $bazId) { a } }" def self.execute!(baz_id) data = client.execute(query: QUERY, variables: { bazId: baz_id }) ActiveRecord::Base.transaction do Foo.create!(a: data.baz.a) BarOperation.execute!(baz_id) end end end class BarOperation QUERY = "query(id: $ID!) { baz(id: $id) { b { c, d } } }" def self.execute!(baz_id) data = client.execute(query: QUERY, variables: { bazId: baz_id }) Bar.create!(c: data.baz.b.c, d: data.baz.b.d) # more complicated logics... end end
The two requests should be merged! class FooOperation QUERY = "query(bazId: $ID!) { baz(id: $bazId) { a, b { c, d } } }" def self.execute!(baz_id) data = client.execute(query: QUERY, variables: { bazId: baz_id }) ActiveRecord::Base.transaction do Foo.create!(a: data.baz.a) BarOperation.execute!(data.baz.b) end end end class BarOperation def self.execute!(b) Bar.create!(c: b.c, d: b.d) # more complicated logics... end end
Problems class FooOperation QUERY = "query(bazId: $ID!) { baz(id: $bazId) { a, b { c, d } } }" def self.execute!(baz_id) data = client.execute(query: QUERY, variables: { bazId: baz_id }) ActiveRecord::Base.transaction do Foo.create!(a: data.baz.a) BarOperation.execute!(data.baz.b) end end end class BarOperation def self.execute!(b) Bar.create!(c: b.c, d: b.d) # more complicated logics... end end `FooOperation` class needs to know what fi elds `BarOperation` uses
Solution: Fragment colocation class FooOperation QUERY = <<~EOS query(bazId: $ID!) { baz(id: $bazId) { a ...BarOperationFragment } } #{BarOperation::Fragment} EOS def self.execute!(baz_id) data = client.execute(query: QUERY, variables: { bazId: baz_id }) ActiveRecord::Base.transaction do Foo.create!(a: data.baz.a) BarOperation.execute!(data.baz) end end end class BarOperation FRAGMENT = <<~EOS fragment BarOperationFragment on Baz { b { c, d } } EOS def self.execute!(baz) Bar.create!(c: baz.b.c, d: baz.b.d) # more complicated logics... end end