クックパッドがどのようにMicroservicesしてきたか/How Cookpad shifts to Microservices

F356bb27a5329c131855abadfd309b7e?s=47 adorechic
October 27, 2016

クックパッドがどのようにMicroservicesしてきたか/How Cookpad shifts to Microservices

F356bb27a5329c131855abadfd309b7e?s=128

adorechic

October 27, 2016
Tweet

Transcript

  1. ΫοΫύου͕ ͲͷΑ͏ʹ .JDSPTFSWJDFTԽ͖͔ͯͨ͠ ΫοΫύουגࣜձࣾ ٕज़෦։ൃج൫άϧʔϓ ٢઒ਸྙ 

  2. 

  3. σΠϦʔ ΞΫηεͷαʔϏε ͲΜͳߏ੒ʹ͠·͔͢ʁ 

  4.  ҰԠ৑௕Խͯ͠୆"QQ %#  ਺ඦ୆·ͰΦʔτεέʔϧͰ͖Δߏ੒ 

  5. αʔϏεཁٻʹରͯ͠ ద੾ͳߏ੒Λߟ͑Δ 

  6. εΫϥονͰαʔϏεΛ্ཱͪ͛Δ ͲΜͳߏ੒ʹ͠·͔͢ʁ 

  7.  .POPMJUIJDΞʔΩςΫνϟ  .JDSPTFSWJDFTΞʔΩςΫνϟ 

  8. .JDSPTFSWJDFT ͍ͭ΍Δ΂͖ʁ 

  9. 

  10. ͜͜·Ͱඞཁʁ 

  11. w ࠷ॳ͔Β.JDSPTFSWJDFTͰ͸ͳ͍ w ϑΣʔζ͝ͱͷ޻෉ͷੵΈॏͶ w ΫοΫύουͷߏ੒ͷมભΛḷΔ 

  12. ˞஫ҙ ࿩ͷྲྀΕΛΘ͔Γ΍͘͢͢ΔͨΊʹ τϐοΫ͝ͱͷ࣌ܥྻ͕લޙͨ͠Γ ͍ۙτϐοΫΛ·ͱΊͨΓ͍ͯ͠·͢ 

  13. w ᴈ໌ظ w ୯ҰαʔϏεɺϞσϧڞ༗ɺ༻్͝ͱͷΠϯϑϥ w αʔϏε֦େظ w ΞϓϦέʔγϣϯංେԽ΁ͷରԠͱݶք w ୤.POPMJUIJDظ

    w ౷Ұతͳ"1*ɺڞ௨ج൫ɺαʔϏε෼ׂ w .JDSPTFSWJDFTԽظ w αʔϏε෼ׂͷฐ֐Λղফ͢Δɺ෼ׂίετͷ௿Լ 
  14. ᴈ໌ظ 

  15. ୯Ұͷ3BJMT DPPLQBE 

  16. ༻్͝ͱʹαʔόʔΛ෼͚͍ͨ w Πϯϑϥͷੑ࣭ͷҧ͍ͰΘ͚ͯ؅ཧ͍ͨ͠ w "1*͸ผυϝΠϯͰ഑৴͢Δ w όοΫάϥ΢ϯυδϣϒ༻ͷαʔόʔΛΘ͚Δ w %#΍Ωϟογϡ؅ཧͳͲ΋ඞཁʹԠͯͦ͡ΕͧΕ෼͚͍ͨ w

    ΞϓϦέʔγϣϯͷ࣮૷͸·ͱΊ͓͖͍ͯͨ 
  17. QVQQFUͷSPMFΛΘ͚ͯผʑʹߏ੒؅ཧ QVQQFU͕ΞϓϦέʔγϣϯͷDPOpHΛ഑෍ DPPLQBE XFC DPPLQBE BQJ DPPLQBE CBDLHSPVOEXPSLFS ΞϓϦέʔγϣϯίʔυ͸શͯಉ͡ɻผϞʔυͱͯ͠ಈ࡞ͤ͞Δ 

  18. ΞϓϦέʔγϣϯؒͰϞσϧΛڞ༗͍ͨ͠ w ػೳ͕େ͖͘ҟͳΔΞϓϦέʔγϣϯΛ෼͚͍ͨ w 1$εϚʔτϑΥϯ޲͚αΠτ w ϑΟʔνϟʔϑΥϯ޲͚αΠτ w ΋ͱ΋ͱϑΟʔνϟʔϑΥϯ޲͚ผαʔϏεͩͬͨͷΛ౷߹ͨ͠ w

    ελοϑ޲͚؅ཧαΠτ w σʔλ͸ಉ͡΋ͷΛݟͯɺϞσϧϩδοΫ΋ڞ༗͍ͨ͠ 
  19. Ϟσϧ΍ڞ௨ϥΠϒϥϦ෦෼ΛTIBSFEͱͯ͠ಠཱ ֤ΞϓϦέʔγϣϯ͔Β͸TZNMJOLͰࢀর DPPLQBE XFC BQJʜ DPPLQBE BENJO DPPLQBE GFBUVSFQIPOF 

  20.  TIBSFEΛؚΊશΞϓϦέʔγϣϯ͕ҰͭͷϦϙδτϦʹಉډ ʮຊମʯʮDPPLQBE@BMMʯͱݺ͹ΕΔ

  21. αʔϏε֦େظ 

  22. ϨγϐҎ֎ͷαʔϏε͕ੜ·Ε࢝ΊΔ w ϨγϐΛͷͤΔɺ͕͢͞Ҏ֎ͷػೳ w ಛച৘ใɺྉཧڭࣨͳͲͷαʔϏεʹͭͳ͕͍ͬͯ͘ w ϓϩτλΠϓΛ࡞ͬͯՁ஋ݕূΛ܁Γฦ͢ w ϓϩτλΠϓͳͷͰܧଓͯ͠࢖͏͔͸ෆ໌ w

    ޻਺Λ࠷খݶʹ͢ΔͨΊʹɺطଘͷࢿ࢈Λ࠷େݶ׆༻ 
  23. ผΞϓϦέʔγϣϯͱ͢Δ ৔߹΋TIBSFEΛڞ༗ ຊମʹ͍͋ͷΓ ʢຊମ͸ڊେԽʣ ೝূɺܾࡁɺϩάͳͲ͸ ຊମͷϞδϡʔϧΛ௚઀࢖͏ ඞཁͳΒαʔϏε͝ͱͷॲཧΛ௚઀࣮૷ 

  24. $*ʹ͔͔Δ͕࣌ؒංେԽ w ͨͩͰ͑͞ςετ͕ͲΜͲΜ૿͕͔͔͑ͯ࣌ؒΔ w TIBSFEΛ௨ͯ͡શ෦ͭͳ͕͍ͬͯΔͷͰશવҧ͏ՕॴͰࢥΘ͵Өڹ͕ ग़ͯςετ͕ࣦഊ͢Δ w मਖ਼ͯ͠࠶࣮ߦʹ·͕͔͔ͨ࣌ؒΔ w ͋ΔνʔϜ͕$*ΛGBJMͤ͞ΔͱଞͷνʔϜ΋σϓϩΠͰ͖ͳ͍

    w σϓϩΠ·Ͱͷ଴ͪ࣌ؒΛ࠷খԽ͍ͨ͠ 
  25. SFNPUF@TQFD ෳ਺୆ͷαʔόʔͰ ςετΛ෼ࢄ࣮ߦ ෼Ҏ಺ʹ ऴΘΔΑ͏ʹ 

  26. ςετ͸͞Βʹ૿͑ଓ͚ͨ w ։ൃ͕ϐʔΫ࣌ͷςετΛ͞͹ͨ͘ΊͷϫʔΧʔ਺૿ w Ұํٳ೔͸શવཁΒͳ͍ w ॊೈʹ૿ݮ͍ͤͨ͞ w ϫʔΧʔͷো֐΍ͨ·ͨ·ࣦഊ͢ΔFYBNQMFͷӨڹ૿ 

  27. 3334QFD w HJUIVCDPNDPPLQBESSSTQFD w &$εϙοτΠϯελϯεΛར༻ͯ͠ίετΛ཈͑Δ w ࣦഊͨ͠ςετͷࣗಈ࠶࣮ߦ 

  28. σϓϩΠʹ͕͔͔࣌ؒΔ w DBQJTUSBOP w ཁ͢ΔʹTTI઀ଓͯ͠σϓϩΠ w ୆਺΋ଟ͘ճͷσϓϩΠͰ෼Ҏ্͔͔Δ w TTIͰࣦഊ͢Δස౓͕૿Ճ w

    ϦτϥΠ͢ΔӋ໨ʹͳΓ͞Βʹ͕͔͔࣌ؒΔ 
  29. NBNJZB w HJUIVCDPNTPSBINBNJZB w 4FSGͰΦʔέετϨʔγϣϯ w $*͕௨ͬͨΒUBSCBMMʹͯ͠4ʹΞοϓ w ։ൃऀ͕४ຊ൪؀ڥͰಈ࡞֬ೝ͍ͯ͠Δؒʹ഑෍ͯ͠४උ w

    σϓϩΠίϚϯυͰ͸੾Γସ͑Δ͚ͩ 
  30. ։ൃ؀ڥ͕ॏ͗͢Δ w खݩͰSBJMTΛىಈͯ͠τοϓදࣔ͢Δ·Ͱ෼Ҏ্͔͔Δ w ͱʹ͔͘HFN΍ൃߦΫΤϦ͕ଟ͗͢Δ w ։ൃ؀ڥͷύϑΥʔϚϯενϡʔχϯά w ։ൃ؀ڥͰ΋ΩϟογϡΛ׆༻͢ΔΑ͏ʹͳΔ w

    ෆཁͳίʔυ୨Է͠ͷܒ໤ 
  31. मਖ਼͕ٴ΅͢Өڹൣғ͕Θ͔Βͳ͍ w ᴈ໌ظ͸ڞ௨Ϟδϡʔϧͱͯ͠੾Γग़ͨ͠Γ"1*Λ੔උ͢ΔͷͰ͸ ͳ͘ɺ௚઀࢖ͬͨΓ֦ுͨ͠Γ͢Δߥʑ͍͠ελΠϧ w TIBSFEͰෳ਺ͷΞϓϦέʔγϣϯ͕ͭͳ͕͍ͬͯͯͲ͏࢖ΘΕ Δͷ͔Θ͔Βͳ͍ w ϥΠϒϥϦ΋ϞϯΩʔύον΍ϑΥʔΫ͍ͯ͠Δ΋ͷ͕ଟ͘஌ͬͯ ͍Δڍಈͱҧ͏

    
  32. ػೳͷڥք͕͍͋·͍ w ͲͷνʔϜ͕୲౰͍ͯ͠Δͷ͔͕͍͋·͍ w ମ੍มߋͳͲͰͷҾ͖ܧ͗࿙Ε΋ൃੜ͕ͪ͠ w ϓϩμΫτΦʔφʔ͸"νʔϜ͚ͩͲ࣮࣭ӡ༻΍࣮૷͸#νʔϜ͕ ΍ͬͪΌͬͯΔ w ػೳมߋ͢Δͱ͖ʹӨڹड͚ΔνʔϜ͕ଟ͍

    w νʔϜΛ·͍ͨͩௐ੔ͱίϛϡχέʔγϣϯ͕େม 
  33. Ͳ͏͢Ε͹ɾɾɾ 

  34. ୤.POPMJUIJDظ 

  35. ୤ຊମ୤TIBSFE͍ͨ͠ w طଘͷࢿ࢈Λ࢖͑Δͱ͍ͬͯ΋ਏΈ͕ڧ͘ͳ͖ͬͯͨ w Ϟδϡʔϧࣗମ͕αʔϏεͱີ݁߹͓ͯ͠Γ݁ہ࠶ར༻ͮ͠Β͍ w εΫϥονͰ࡞Ε͹ίʔυϕʔε΋খ͘͞ࡁΉ w ґଘ͕গͳ͘։ൃ؀ڥͷಈ࡞΍ςετ΋଎͍ w

    গͳ͘ͱ΋৽نͰ࡞ΔͳΒ෼͚ͨ΄͏͕Α͍ͷͰ͸ 
  36. ೝূͳͲຊମͱͷ΍ΓͱΓ͸ "1*Λ௨ͯ͡ߦ͏ ίʔυ΋%#΋ ຊମ͔Βಠཱ ܾࡁͷΑ͏ʹ ڞ௨ͯ͠ར༻Ͱ͖Δ ػೳΛ੾Γग़͠ ੾Γग़͞Εͨػೳ͸ ຊମ͔Β΋"1*࿈ܞ 

  37. "1*Λ௨ͯ͠ϦιʔεΛѻ͏ w J04"OESPJEΞϓϦ͕ߴػೳԽ w 8FC7JFXͰఏڙ͍ͯͨ͠΋ͷ΋ωΠςΟϒ࣮૷Խ w "1*ͰຊମͷϦιʔεΛࡉ੍͔͘ޚͰ͖ΔΑ͏ʹ͢Δ w ΠϯλʔϑΣΠεΛ౷Ұ͍ͨ͠ w

    ϑΥʔϚοτͷҟͳΔ"1*͕ෳ਺ଘࡏ͍ͯͨ͠ w "1*͝ͱʹYYYDMJFOU 
  38. 3&45GVMIZQFSNFEJB"1* GET /v1/users/123 { "id": 123, "name": "ύυඒ", "kitchen": {

    "id": 15, "created": "2016-03-10T10:59:24+09:00", } }, "_links": { "self": { "href": "/v1/users/123" }, "recipes": { "href": "/v1/users/123/recipes" }, } } Ϧιʔεؒͷؔ࿈Λ ϦϯΫͱͯ͠දݱͰ͖Δ 
  39. (BSBHF w HJUIVCDPNDPPLQBEHBSBHF class Employee < ActiveRecord::Base include Garage::Representer belongs_to

    :division has_many :projects property :id property :title property :division, selectable: true collection :projects, selectable: true link(:division) { division_path(division) } link(:projects) { employee_projects_path(self) } def self.build_permissions(perms, other, target) perms.permits! :read end end Ϧιʔεͱͯ͠ͷ ଐੑ΍ϦϯΫΛఆٛ ೝՄ৚݅΋ఆٛͰ͖Δ 
  40. (BSBHF$MJFOU w HJUIVCDPNDPPLQBEHBSBHF@DMJFOU # GET https://garage.example.com/v1/me user = client.get("/me") user.id

    user.name # GET https://garage.example.com/v1/recipes recipes = client.get("/recipes") recipes.total_count recipes[0].id recipes[0].name ϦιʔεΛจࣈྻͰࢦఆ "1*ͷ࣮૷͕૿͑ͯ΋ ΫϥΠΞϯτ͸ͦͷ··࢖͑Δ ͲͷαʔϏεΛ࢖͏ͱ͖΋ ࢖͍ํ͸ಉ͡ ֤ΤϯυϙΠϯτͷ࢓༷͚ͩ Θ͔Ε͹Α͍ 
  41. "VUPEPD w HJUIVCDPNSLBNVSBBVUPEPD # spec/requests/users_spec.rb describe "Users" do describe "GET

    /v1/me", autodoc: true do it "returns a current_resource_owner" do get "/v1/me", params: {}, headers: headers expect(response).to have_http_status(:success) expect(response.body).to be_json_as( id: resource_owner.id, name: resource_owner.name ) end end end ςετ͔ΒυΩϡϝϯτΛ ࣗಈੜ੒ 
  42. ೝূɺϩάɺ௨஌ͳͲ༷ʑͳ ڞ௨ج൫αʔϏε͕੔උ͞Ε ͍ͯͬͨ TIBSFE࿈ܞ͍ͯͨ͠αʔϏε΍ ຊମ಺͔Βଔۀ͢ΔαʔϏε͕ ग़͖ͯͨ ຊମ͸ґଘؔ܎౳ͷ໰୊Ͱ HBSBHF"1*ΛผϞʔυͰىಈ ΞϓϦ΋ผαʔϏε΋ ಉ͡"1*Λ࢖͏

    ֤αʔϏεؒ΋ HBSBHF"1*Ͱ࿈ܞ 
  43. .JDSPTFSWJDFTԽظ 

  44. ߏ੒؅ཧ͕େม w 8FCόονͳͲ༻్ʹԠͯ͡ߏ੒؅ཧΛ෼͚ΔελΠϧ w BQQαʔόʔ͸ಠཱͨ͠SPMF w όονδϣϒ͸ڞ௨ͷόονϫʔΧʔͷҰ෦ͱͯ͠؅ཧ w ઃఆͷ഑෍࿙Ε w

    ΞϓϦέʔγϣϯ͕ಉډ͢Δͱݖݶ؅ཧ͕ࠔ೉ w *".3PMF΍ൿಗ஋ͷ؅ཧͳͲ 
  45. %PDLFS w ϙʔλϒϧͳ࣮ߦ؀ڥ w TUBHJOHQSPEVDUJPOόονಉ͡Πϝʔδ w खݩͰݕূ͢Δ͜ͱ΋Ͱ͖Δ w %PDLFSpMF͸ΞϓϦέʔγϣϯϦϙδτϦʹஔ͘ w

    ΞϓϦέʔγϣϯݻ༗ͷ৘ใ͕ू໿ w ؀ڥґଘ஋͸؀ڥม਺ͱͯ͠σϓϩΠ࣌ʹ஫ೖ 
  46. FUDFOWFUDWBVMU w HJUIVCDPNTPSBIFUDFOW w FUDEͰઃఆ஋Λ؅ཧ w HJUIVCDPNTPSBIFUDWBVMU w FUDEͷ஋Λ҉߸Խ w

    ΋ͱ΋ͱFUDEʹ"$-͕ແ͔ͬͨͨΊ࡞ΒΕͨ w ࢦఆͷ伴Λ͍࣋ͬͯΔΠϯελϯεͰ͔͠෮߸Ͱ͖ͳ͍ 
  47. FUDXFC w HJUIVCDPNTPSBIFUDXFC 8FC6*ͰશαʔϏεͷ ઃఆ஋ΛҰׅ؅ཧ ൿಗ஋Λѻ͏ͷͰ ݖݶΛ࣋ͭਓ͚͕ͩૢ࡞ 

  48. ,VSPLP w HJUIVCDPNDPPLQBELVSPLP w શαʔϏεͷόονδϣϒ΍ϫʔΫϑϩʔΛ؅ཧ w ϫʔΧʔ͕࠷৽ͷ%PDLFSΠϝʔδΛऔಘ࣮ͯ͠ߦ 8FCͰδϣϒ؅ཧ ϩάӾཡ ࠶࣮ߦ·ͰͰ͖Δ

    
  49. #BSCFRVF w HJUIVCDPNDPPLQBECBSCFRVF w ,VSPLPಉ༷%PDLFSίϯςφͰδϣϒ࣮ߦͰ͖Δ 

  50. %PDLFSӡ༻ͷચ࿅ w ౰ॳ͸খ͞ͳπʔϧΛ૊Έ߹Θͤͯ؅ཧ͍ͯͨ͠ w ౷Ұͯ͠ίϯτϩʔϧ͢Δ΋ͷ͕ͳ͍ w ઃఆ͢Δ΋ͷ͕݁ߏଟ͍ w ϗετͷ؅ཧͷखؒ w

    &$4ͷొ৔ w "84ϚωʔδυͳίϯςφαʔϏε 
  51. )BLP w HJUIVCDPNFBHMFUNUIBLP w %PDLFSΞϓϦ༻ͷσϓϩΠπʔϧ w ΫοΫύουͰ͸όοΫΤϯυʹ&$4Λར༻ w ΞϓϦέʔγϣϯ͝ͱͷઃఆ͸:".-Ͱ؅ཧ w

    ؀ڥ͝ͱʹ؀ڥม਺ΛઃఆͰ͖Δ w ൿಗ஋ͷΈFUDFOWFUDWBVMUͰ؅ཧ 
  52. ൥ࡶͳ؅ཧ͔Βͷղ์ w ͱʹ͔͘%PDLFSΠϝʔδ͕͋Ε͹༷ʑͳ༻్Ͱ࣮ߦͰ͖Δ w Ϋϥ΢υ্ͷݖݶ؅ཧ͕γϯϓϧʹ w &$45BTLʹ*".3PMFͰݖݶ෇༩ w όονδϣϒ͸σϓϩΠͷ֓೦͕ͳ͘ͳͬͨ w

    ͦͷ࣌఺Ͱ࠷৽ͷΠϝʔδΛऔಘ࣮ͯ͠ߦ͞ΕΔ w TTIͯ͠ϩάௐࠪ͢Δ͜ͱ͸ͳ͘ͳΓɺ8FC6*Ͱ֬ೝ 
  53. ΞϓϦέʔγϣϯ௥Ճ͕௿ίετԽ w %PDLFSΠϝʔδ͕͋Ε͹0, w XFCCBUDIKPCRVFVFͲ͜Ͱ΋࢖͑Δ w HBSBHF@DMJFOU͚ͩೖΕ͓͚ͯ͹ଞͷαʔϏε͕࢖͑Δ w ҎલͳΒϞʔυΛΘ͚ͨΓ͍ͯͨ͠΋ͷ΋৽نͰ௥Ճͨ͠ํָ͕ w

    αʔϏεͷཻ౓͸࣍ୈʹখ͘͞ͳΓɺ૿͑Δ଎౓΋૿͍ͯ͘͠ 
  54. #BDLFOE'PS'SPOUFOE Ϧιʔε͸ಉ͡΋ͷ ఏڙ͍͕ͨ͠ ೝূํ͕ࣜҟͳΔͳͲ ಛघͳΫϥΠΞϯτ ઐ༻όοΫΤϯυ 

  55. "1*࢓༷ͷᴥᴪʹΑΔࣄނ w ഁյతͳ࢓༷มߋʹΑΔࣄނ w ଟ͘ͷ৔߹͸ҙਤͨ͠΋ͷͰ͸ͳ͘ൃੜ w ҙਤ͍ͯ͠Δ৔߹΋Ͳ͔͜Βར༻͞Ε͍ͯΔͷ͔೺Ѳͮ͠Β͍ w ςετ͸ʁ w

    ࣗಈςετͰ͸ଞαʔϏεͷ"1*͸ελϒ͍ͯ͠Δ w "1*ϓϩόΠμଆ͕࢓༷มߋͯ͠΋ελϒ͸ߋ৽͞Εͳ͍ͷͰݕ஌Ͱ͖ͳ͍ 
  56. WDS w HJUIVCDPNWDSWDS w ςετ࣌ʹ࣮ࡍͷ)551ͷϦΫΤετͱϨεϙϯεΛه࿥ w ࣍ճҎ߱ͷϦΫΤετͰ͸ه࿥ͨ͠Χηοτσʔλ͔ΒڍಈΛ࠶ݱ ͢Δ w ࣮ϦΫΤετ͔ΒελϒΛੜ੒͢Δ

    
  57. 3BDL7$3 w HJUIVCDPNNJZBHBXBSBDLWDS w "1*ϓϩόΠμଆ͕ࣗ਎Λςετͨ͠ΧηοτσʔλΛه࿥ɾ഑෍ w "1*ΫϥΠΞϯτଆ͸ςετ࣌"1*ϓϩόΠμ͔ΒΧηοτσʔλ Λऔಘͯࣗ͠਎Λςετ͢Δࡍͷελϒͱ͢Δ w ΫϥΠΞϯτ͸ৗʹ࠷৽ͷڍಈͷελϒΛ࢖ͬͯςετͰ͖Δ

    
  58. $*࣮ߦස౓ͷ͕ࠩେ͖͍৔߹ͷ໰୊ w ։ൃ͕׆ൃͰҰ೔ʹԿ౓΋$*࣮ߦʴσϓϩΠ͞ΕΔ΋ͷ΋͋Ε͹ɺ Ұ೔ʹҰճఔ౓͔͠$*͕࣮ߦ͞Εͳ͍΋ͷ΋͋Δ w 3BDL7$3͸ΫϥΠΞϯτଆͰ࣮ߦ͞Εͯ͸͡Ίͯ࢓༷͕յΕͨ ͜ͱΛݕ஌Ͱ͖Δ w ΫϥΠΞϯτଆͷ$*ස౓͕গͳ͍ͱɺ"1*ϓϩόΠμଆͷมߋΛ ݕ஌͢ΔલʹσϓϩΠ͞Εͯ͠·͏

    
  59. $POTVNFS%SJWFO$POUSBDUUFTUJOH w ΫϥΠΞϯτʢ$POTVNFSʣ͕"1*Λελϒͯ͠ςετ w ظ଴͢ΔৼΔ෣͍Λܖ໿ʢ$POUSBDUʣͱͯ͠"1*ଆʹ౉͢ w "1*ϓϩόΠμଆ͸ࣗ਎͕$POUSBDUΛຬ͍ͨͯ͠Δ͔Λςετ͢ Δ w "1*ϓϩόΠμଆͷ$*ͰςετͰ͖ΔͷͰɺ໰୊ʹͳΔϦϏδϣ

    ϯΛσϓϩΠ͢Δલʹݕ஌Ͱ͖Δ http://martinfowler.com/articles/consumerDrivenContracts.html 
  60. 1BDU w HJUIVCDPNSFBMFTUBUFDPNBVQBDU w ΫϥΠΞϯτଆ w $*ͰQBDUϑΝΠϧΛੜ੒ w "1*ϓϩόΠμଆ w

    $*ͰQBDUϑΝΠϧΛWFSJGZ IUUQTHJUIVCDPNSFBMFTUBUFDPNBVQBDUIPXEPFTJUXPSL 
  61. 1BDU $POTVNFS describe 'get_all' do let(:recipe_a) { { id: Pact.like(1),

    name: Pact.like('Curry') } } let(:recipe_b) { { id: Pact.like(2), name: Pact.like('Salada') } } before do provider_app.given('there are 2 recipes'). upon_receiving('a request for recipes'). with(method: :get, path: '/v1/recipes'). will_respond_with( status: 200, headers: { 'Content-Type' => Pact.term( generate: 'application/json', matcher: %r{application/json} ), }, body: [recipe_a, recipe_b] ) end it 'returns recipes' do recipes = described_class.get_all expect(recipes.size).to eq(2) expect(recipes.first.name).to eq('Curry') end end ςετ͸௨ৗͱಉ͡ 1BDUͰελϒ 
  62. 1BDUpMF { "consumer": { "name": "ConsumerApp" }, "provider": { "name":

    "ProviderApp" }, "interactions": [ { "description": "a request for recipes", "provider_state": "there are 2 recipes", "request": { "method": "get", "path": "/v1/recipes" }, "response": { "status": 200, "headers": { "Content-Type": { "json_class": "Pact::Term", "data": { "generate": "application/json", "matcher": { "json_class": "Regexp", "o": 0, "s": "application/json" } ϦΫΤετͱ Ϩεϙϯεͷ ಺༰ΛKTPOͰग़ྗ 
  63. 1BDU 1SPWJEFS w "1*ଆ w γφϦΦʹԊͬͨηοτΞοϓίʔυ͚ͩΛ༻ҙ Pact.provider_states_for 'ConsumerApp' do provider_state

    "there are 2 recipes" do set_up do %w[Curry Salada].each {|name| Recipe.create!(name: name) } end end end 
  64. ো֐ͷ఻೻ w ࣮૷ʹόά͕ͳ͔Ζ͏ͱো֐͸ى͜Γ͏Δ w ͋ΔαʔϏε͕ো֐ʹͳΔͱͦΕΛར༻͍ͯ͠ΔαʔϏεʹ఻೻ w ϦΫΤετ͝ͱʹλΠϜΞ΢τ·Ͱ଴ͭ͜ͱͰΫϥΠΞϯτଆ΋ ٧·Δ w ΫϥΠΞϯτଆͷϦτϥΠػߏ͕"1*ϓϩόΠμʹͱͲΊΛࢗ͢

    
  65. $JSDVJU#SFBLFS w ฏৗ࣌ͷࣦഊ͸ΫϥΠΞϯτ͸ϦτϥΠͰ͖Δ w "1*ϓϩόΠμ͕μ΢ϯ͍ͯ͠Δ৔߹͸ϦΫΤετ͠ͳ͍Α͏ʹ͢Δ w λΠϜΞ΢τ଴ͪ΋͠ͳ͍ w ͠͹Βͯ͘͠ϓϩόΠμ͕෮׆ͨ͠Β·ͨϦΫΤετΛ࠶։͢Δ 

  66. &YQFEJUPS w HJUIVCDPNDPPLQBEFYQFEJUPS EXPEDITOR_SERVICE = Expeditor::Service.new( non_break_count: 20, threshold: 0.2,

    period: 10, sleep: 5, ) def notification_counts Expeditor::Command.new(service: EXPEDITOR_SERVICE, timeout: 3) { response = client.get("/notifications/counts", params, options) response.notification_count }.set_fallback {|e| Raven.capture_exception(e) 0 }.start(current_thread: true).get end $JSDVJU#SFBLFSͷᮢ஋Λઃఆ Τϥʔ࣌͸ϩάΛه࿥ͯ͠ σϑΥϧτ஋Λฦ͢ 
  67. &YQFEJUPS w ฏৗ࣌  ΫϥΠΞϯταʔϏε ΦϓγϣϯʹԠͯ͡ ϦτϥΠͨ͠Γ Ͳ͏ͯ͠΋ͩΊͳΒ GBMMCBDLॲཧ "1*ϓϩόΠμ

  68. &YQFEJUPS w ো֐࣌  ΫϥΠΞϯταʔϏε ϦΫΤετͤͣ ࠷ॳ͔ΒGBMMCBDLॲཧ "1*ϓϩόΠμ

  69. αʔϏε෼ׂ࣌ʹࠔΔϙΠϯτ͕ղܾ͞Ε͖ͯͨ w "1*͕ཚཱͯ͠Ͳ͜ΛͲ͏࢖͑͹͍͍ͷ͔Θ͔Βͳ͘ͳΔ w (BSBHFͰͲͷαʔϏε΋ಉ͡Α͏ʹ࢖͑Δ w ຖճαʔόʔ࡞ͬͯߏ੒؅ཧ͢Δͷ͕େม w %PDLFSpMFͱ:".-Λॻ͚͹)BLPͰ؀ڥ༻ҙͰ͖Δ w

    αʔϏεڥքͰόά΍ো֐ʹͳΓ΍͍͢ w 1BDU͕ޓ׵ੑΛ୲อ͠&YQFEJUPS͕ো֐ͷ఻೻Λ๷͙ 
  70. αʔϏεΛ෼ׂ͢Δ͜ͱͰಘΒΕΔྑ͍͜ͱ w ίʔυϕʔε͕খ͍͞ w ςετ΍։ൃ؀ڥͷಈ࡞͕଎͍ w มߋʹΑΔӨڹൣғ͕খ͍͞ w طଘ࣮૷ʹΑΔ੍໿͕খ͍͞ w

    νʔϜʹ࣮͋ͬͨ૷ϧʔϧ w ػೳʹదͨ͠ϥΠϒϥϦɺݴޠͷબ୒ 
  71. αʔϏεΛ෼ׂ͢Δ͜ͱͰಘΒΕΔྑ͍͜ͱ w γεςϜڥք͕໌֬ w νʔϜ಺Ͱίϛϡχέʔγϣϯ͕׬݁͢Δ w ׬݁Ͱ͖ͳ͍৔߹ڥքͱͯ͋͠·ΓΑ͘ͳ͍ 

  72. ·ͱΊ w ࠷ॳ͔Βɺ͋Δ͍͸͋Δ೔ಥવ.JDSPTFSWJDFTʹͳͬͨΘ͚Ͱ͸ͳ͍ w ͦͷ౎౓໰୊ʹͳͬͨ͜ͱʹରԠ͖ͯͨ͠ੵΈॏͶ w ϞϊϦγοΫͳγεςϜ͸ঃʑʹਏΈ͕େ͖͘ͳ͍ͬͯ͘ w αʔϏεΛ෼͚Δ͜ͱͰൃੜ͢Δ໰୊͸ٕज़ͰճආͰ͖Δ w

    ςΫχοΫΛ஌ΓϑΣʔζʹԠͨ͡ઃܭΛ͢Δͷ͕ॏཁ