Upgrade to Pro — share decks privately, control downloads, hide ads and more …

みんなで育てる GraphQL スキーマ, それを支える Protobuf / GraphQL...

みんなで育てる GraphQL スキーマ, それを支える Protobuf / GraphQL and Protobuf #tech_stand

Masayuki Izumi

March 03, 2022
Tweet

More Decks by Masayuki Izumi

Other Decks in Programming

Transcript

  1. ©2021 Wantedly, Inc. (SBQI2-#''΍ΊΔ ˞׬શҠߦ͸ͯ͠ͳ͍ ‣ ͬ͘͟Γݴ͏ͱ 
 #''͕8BOUFEMZͷશମͷΞʔΩςΫνϟʹ 


    ͋·ΓϚονͯ͠ͳ͔ͬͨ ‣ ˞͜ͷl#''z͸ʮ͋ΔϑϩϯτΤϯυઐ༻ͷɺ ϑϩϯτΤϯυ͕ΦʔφʔγοϓΛ࣋ͭ"1* TFSWFSʯ͘Β͍ͷχϡΞϯε ͜Ε·Ͱͷ͋Β͢͡ @izumin5210, GraphQL ಋೖͷ൓লͱ࠶௅ઓ, JSConf JP 2021 @Altech, ٕज़Λతʹ౰ͯΔٕज़ʹ͍ͭͯ - GraphQL ΛೖΕ௚ͨ͠࿩, ٢঵ࣉ.pm28
  2. ©2021 Wantedly, Inc. (SBQI2-(BUFXBZ ͸͡Ί·ͨ͠ ˞׬શҠߦ͸ͯ͠ͳ͍ ‣ ͬ͘͟Γݴ͏ͱ  1SPUPCVG͔Β(SBQI2-εΩʔϚΛੜ੒͢Δ

     શΞϓϦͰಉ͡(SBQI2-εΩʔϚɾαʔόΛ ࢖͏ ‣ ࠓ೔͸(SBQI2-(BUFXBZͷઃܭɾ࣮૷ͳͲΛ ঺հ͠·͢ ͜Ε·Ͱͷ͋Β͢͡ @izumin5210, GraphQL ಋೖͷ൓লͱ࠶௅ઓ, JSConf JP 2021 @Altech, ٕज़Λతʹ౰ͯΔٕज़ʹ͍ͭͯ - GraphQL ΛೖΕ௚ͨ͠࿩, ٢঵ࣉ.pm28
  3. ©2021 Wantedly, Inc. @izumin5210 ‣ "SDITRVBE8BOUFEMZ *OD  #BDLFOE 8FC'SPOUFOEͷ5FDI-FBEతͳ͜ͱ΋͍ͯ͠·͢

     ୅ද࡞  HSBQJ(PͷH31$TFSWFS༻ϚΠΫϩϑϨʔϜϫʔΫ  6*σβΠϯγεςϜͷ3FBDU࣮૷ͷઃܭ  (SBQI2-(BUFXBZͷઃܭɾ࣮૷ ˡࠓ೔͸͜ͷ࿩ʣ ‣ ؾʹͳΔ(SBQI2-4QFD3'$͸$MJFOUDPOUSPMMFEOVMMBCJMJUZPQFSBUPS  IUUQTHJUIVCDPNHSBQIRMHSBQIRMTQFDJTTVFT  %JSFDUJWFೖΕΔ࿩͔ͱࢥͬͨΒɺ4ZOUBYͷ֦ுͩͬͨ
  4. ©2021 Wantedly, Inc. (SBQI2-#''΍ΊΔ ˞׬શҠߦ͸ͯ͠ͳ͍ ‣ ͬ͘͟Γݴ͏ͱ 
 #''͕8BOUFEMZͷશମͷΞʔΩςΫνϟʹ 


    ͋·ΓϚονͯ͠ͳ͔ͬͨ ‣ ˞͜ͷl#''z͸ʮ͋ΔϑϩϯτΤϯυઐ༻ͷɺ ϑϩϯτΤϯυ͕ΦʔφʔγοϓΛ࣋ͭ"1* TFSWFSʯ͘Β͍ͷχϡΞϯε <࠶ܝ>͜Ε·Ͱͷ͋Β͢͡ @izumin5210, GraphQL ಋೖͷ൓লͱ࠶௅ઓ, JSConf JP 2021 @Altech, ٕज़Λతʹ౰ͯΔٕज़ʹ͍ͭͯ - GraphQL ΛೖΕ௚ͨ͠࿩, ٢঵ࣉ.pm28
  5. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. 8BOUFEMZͷόοΫΤϯυ ϚΠΫϩαʔϏεΞʔΩςΫνϟͰ͋Δ 
 QSPUPʹυϝΠϯ஌͕ࣝϞσϦϯά͞Ε͍ͯΔ 8BOUFEMZʹ͓͚Δ(SBQI2-ӡ༻্ͷ՝୊

    QSPUP্ͷ஌ࣝ(SBQI2-ʹಉظ͞Εͳ͍ ϑϩϯτΤϯυΤϯδχΞ͕QSPUPΛࢀর͠ʹ͍͘ྗֶ͸ಇ͔ͳ͍ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ
  6. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. 8BOUFEMZͷόοΫΤϯυ ϚΠΫϩαʔϏεΞʔΩςΫνϟͰ͋Δ 
 QSPUPʹυϝΠϯ஌͕ࣝϞσϦϯά͞Ε͍ͯΔ 8BOUFEMZʹ͓͚Δ(SBQI2-ӡ༻্ͷ՝୊

    QSPUP্ͷ஌ࣝ(SBQI2-ʹಉظ͞Εͳ͍ ϑϩϯτΤϯυΤϯδχΞ͕QSPUPΛࢀর͠ʹ͍͘ྗֶ͸ಇ͔ͳ͍ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ ˠ1SPUPCVG͔Β0QFO"1* 4XBHHFS ͷεΩʔϚΛు͚ΔͷͰɺ (SBQI2-Ͱ͋Δඞཁ͕ͳ͍ʜ
  7. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. 8BOUFEMZͷόοΫΤϯυ ϚΠΫϩαʔϏεΞʔΩςΫνϟͰ͋Δ 
 QSPUPʹυϝΠϯ஌͕ࣝϞσϦϯά͞Ε͍ͯΔ 8BOUFEMZʹ͓͚Δ(SBQI2-ӡ༻্ͷ՝୊

    QSPUP্ͷ஌ࣝ(SBQI2-ʹಉظ͞Εͳ͍ ϑϩϯτΤϯυΤϯδχΞ͕QSPUPΛࢀর͠ʹ͍͘ྗֶ͸ಇ͔ͳ͍ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ ˠ1SPUPCVG͔Β0QFO"1* 4XBHHFS ͷεΩʔϚΛు͚ΔͷͰɺ (SBQI2-Ͱ͋Δඞཁ͕ͳ͍ʜ )PXOPUUPMFBSO(SBQI2-5IF(VJME#MPH IUUQTXXXUIFHVJMEEFWCMPHIPXOPUUPMFBSOHSBQIRM
  8. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. 8BOUFEMZͷόοΫΤϯυ ϚΠΫϩαʔϏεΞʔΩςΫνϟͰ͋Δ 
 QSPUPʹυϝΠϯ஌͕ࣝϞσϦϯά͞Ε͍ͯΔ 8BOUFEMZʹ͓͚Δ(SBQI2-ӡ༻্ͷ՝୊

    QSPUP্ͷ஌ࣝ(SBQI2-ʹಉظ͞Εͳ͍ ϑϩϯτΤϯυΤϯδχΞ͕QSPUPΛࢀর͠ʹ͍͘ྗֶ͸ಇ͔ͳ͍ (SBQI2-ͷϝϦοτ ʢ࠶ར༻Մೳͳ ʣΦϒδΣΫτάϥϑͷߏங બ୒తσʔλऔಘ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ ෳ਺ϚΠΫϩαʔϏε͔ΒσʔλΛू໿͢Δ(SBQI2-αʔόΛ࡞Γɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ
  9. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2- ܕͷੜ੒ GraphQL Protobuf // ブログ投稿を表すオブジェクト。 message

    Post { // Required. uint64 id = 1; // Required. 投稿のタイトル。 string title = 2; // Required. 記事の状態。 State state = 3; enum State { STATE_UNSPECIFIED = 0; // 下書き STATE_DRAFT = 1; // 公開済み STATE_PUBLISHED = 2; } } Generate # ブログ投稿を表すオブジェクト。 type Post { # Required. id: String! # Required. 投稿のタイトル。 title: String! # Required. 記事の状態。 state: State! } enum PostState { # 下書き DRAFT # 公開済み PUBLISHED }
  10. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2- ܕͷੜ੒ GraphQL Protobuf // ブログ投稿を表すオブジェクト。 message

    Post { // Required. uint64 id = 1; // Required. 投稿のタイトル。 string title = 2; // Required. 記事の状態。 State state = 3; enum State { STATE_UNSPECIFIED = 0; // 下書き STATE_DRAFT = 1; // 公開済み STATE_PUBLISHED = 2; } } Generate # ブログ投稿を表すオブジェクト。 type Post { # Required. id: String! # Required. 投稿のタイトル。 title: String! # Required. 記事の状態。 state: State! } enum PostState { # 下書き DRAFT # 公開済み PUBLISHED } ίϝϯτΛ൓өͯ͠Δͷ΋ॏཁͳϙΠϯτ
  11. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2-/FYVT GraphQL Nexus const Post = objectType({

    name: "Post", definition(t) { t.field("title", { type: nonNull("String"), description: "...", resolver(root) { // .proto から生成した message return root.getTitle(); } }); // ... } }); Generate ܕͷੜ੒ίʔυͷੜ੒ Protobuf // ブログ投稿を表すオブジェクト。 message Post { // Required. uint64 id = 1; // Required. 投稿のタイトル。 string title = 2; // Required. 記事の状態。 State state = 3; enum State { STATE_UNSPECIFIED = 0; // 下書き STATE_DRAFT = 1; // 公開済み STATE_PUBLISHED = 2; } }
  12. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2-/FYVT GraphQL Nexus const Post = objectType({

    name: "Post", definition(t) { t.field("title", { type: nonNull("String"), description: "...", resolver(root) { // .proto から生成した message return root.getTitle(); } }); // ... } }); Generate ܕͷੜ੒ίʔυͷੜ੒ Protobuf // ブログ投稿を表すオブジェクト。 message Post { // Required. uint64 id = 1; // Required. 投稿のタイトル。 string title = 2; // Required. 記事の状態。 State state = 3; enum State { STATE_UNSPECIFIED = 0; // 下書き STATE_DRAFT = 1; // 公開済み STATE_PUBLISHED = 2; } } 8BOUFEMZͰ͸ (SBQI2-/FYVT 5ZQF4DSJQU Λར༻
  13. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2-/FYVT GraphQL Nexus const Post = objectType({

    name: "Post", definition(t) { t.field("title", { type: nonNull("String"), description: "...", resolver(root) { // .proto から生成した message return root.getTitle(); } }); // ... } }); Generate ܕͷੜ੒ίʔυͷੜ੒ Protobuf // ブログ投稿を表すオブジェクト。 message Post { // Required. uint64 id = 1; // Required. 投稿のタイトル。 string title = 2; // Required. 記事の状態。 State state = 3; enum State { STATE_UNSPECIFIED = 0; // 下書き STATE_DRAFT = 1; // 公開済み STATE_PUBLISHED = 2; } } 8BOUFEMZͰ͸ (SBQI2-/FYVT 5ZQF4DSJQU Λར༻ 1SPUPUP(SBQI2-ͷม׵ίʔυ΋ੜ੒
  14. ©2021 Wantedly, Inc. 1SPUP͔Βͷσʔλू໿ɾάϥϑߏங Ͳ͏͍͏ΞʔΩςΫνϟͰ࣮ݱ͢Δʁ 1SPEVDUJPO3FBEZ(SBQI2-ͱ͍͏ຊͰ͸ɺ(SBQI2-(BUFXBZͷ࣮૷ύλʔϯͱͯ͠ҎԼͷͭΛ঺հ͍ͯ͠Δ ʢεϖʔεͷؔ܎Ͱઆ໌͕ࡶͳͷͰɺਖ਼֬ͳ৘ใ͸ຊಡΉ͔άά͍ͬͯͩ͘͞🙏ʣ ‣ 5IFl4JNQMFzXBZ୯७ͳϓϩΩγͱͯ͠ৼΔ෣͏ɻεΩʔϚ͸ޙΖͷ31$ͷܗʹͳΔʢάϥϑʹͳΒͳ͍ʣ ‣

    4DIFNB4UJUDIJOHෳ਺ͷ(SBQI2-εΩʔϚΛ߹੒ɻؔ࿈͸FYUFOEͰఆٛ SFTPMWFS͸(BUFXBZʹ࣮૷ɻ ‣ "QPMMP4DIFNB'FEFSBUJPOσΟϨΫςΟϒΛ͏·͘࢖ͬͯɺεΩʔϚΛ·͍ͨͩؔ࿈Λهड़Ͱ͖ͨΓ͢Δɻ ‣ 4JOHMF4DIFNB(BUFXBZ  ʢ্͕ͭ4DIFNB͝ͱ%FDFOUSBMJ[F͢Δͷʹରͯ͠ʣ$FOUSBMJ[Fͳ··ѻ͏  ϏδωεϩδοΫ͸όοΫΤϯυͷαʔϏε܈Ͱ࣋ͪɺ(BUFXBZʹ͸άϧʔίʔυͷΈهड़͢Δ 1SPUPCVG(SBQI2- Production Ready GraphQL ͸ GraphQL ʹؔ͢Δ࠷΋ྑ͍ࢿྉͷҰͭͳͷͰɺͥͻಡΈ·͠ΐ͏ https://book.productionreadygraphql.com/
  15. ©2021 Wantedly, Inc. 1SPUP͔Βͷσʔλू໿ɾάϥϑߏங Ͳ͏͍͏ΞʔΩςΫνϟͰ࣮ݱ͢Δʁ 1SPEVDUJPO3FBEZ(SBQI2-ͱ͍͏ຊͰ͸ɺ(SBQI2-(BUFXBZͷ࣮૷ύλʔϯͱͯ͠ҎԼͷͭΛ঺հ͍ͯ͠Δ ʢεϖʔεͷؔ܎Ͱઆ໌͕ࡶͳͷͰɺਖ਼֬ͳ৘ใ͸ຊಡΉ͔άά͍ͬͯͩ͘͞🙏ʣ ‣ 5IFl4JNQMFzXBZ୯७ͳϓϩΩγͱͯ͠ৼΔ෣͏ɻεΩʔϚ͸ޙΖͷ31$ͷܗʹͳΔʢάϥϑʹͳΒͳ͍ʣ ‣

    4DIFNB4UJUDIJOHෳ਺ͷ(SBQI2-εΩʔϚΛ߹੒ɻؔ࿈͸FYUFOEͰఆٛ SFTPMWFS͸(BUFXBZʹ࣮૷ɻ ‣ "QPMMP4DIFNB'FEFSBUJPOσΟϨΫςΟϒΛ͏·͘࢖ͬͯɺεΩʔϚΛ·͍ͨͩؔ࿈Λهड़Ͱ͖ͨΓ͢Δɻ ‣ 4JOHMF4DIFNB(BUFXBZ  ʢ্͕ͭ4DIFNB͝ͱ%FDFOUSBMJ[F͢Δͷʹରͯ͠ʣ$FOUSBMJ[Fͳ··ѻ͏  ϏδωεϩδοΫ͸όοΫΤϯυͷαʔϏε܈Ͱ࣋ͪɺ(BUFXBZʹ͸άϧʔίʔυͷΈهड़͢Δ 1SPUPCVG(SBQI2- Production Ready GraphQL ͸ GraphQL ʹؔ͢Δ࠷΋ྑ͍ࢿྉͷҰͭͳͷͰɺͥͻಡΈ·͠ΐ͏ https://book.productionreadygraphql.com/ On GraphQL Schema Stitching & API Gateways | by Marc-André Giroux | Medium https://xuorig.medium.com/on-graphql-schema-stitching-api-gateways-5dcb579fa90f ͜ͷهࣄ͸ Wantedly ࣾ಺Ͱͷ Production Ready GraphQL ྠಡձͰڞ༗͞Ε·ͨ͠ 4JOHMF4DIFNB(BUFXBZͷΠϝʔδਤ 1SPEVDUJPO3FBEZ(SBQI2-ஶऀͷϒϩά͔ΒҾ༻ 4JOHMF4DIFNB(BUFXBZͱ͍͏୯ޠ͸ग़ͯͳ͍͕ɺ ಉ͡΋ͷΛࢦ͍ͯͦ͠͏ 8BOUFEMZͰ͸4JOHMF4DIFNB(BUFXBZΛ࠾༻ ௕ظతʹͲ͏ͳΔ͔͸Θ͔Βͳ͍͕ɺ 4UJUDIJOH΍'FEFSBUJPOͰதԝूݖԽΛճආͰ͖ΔϝϦοτΑΓɺ ॳखͰ͸ߏ੒͕ෳࡶʹͳΔσϝϦοτͷ΄͏͕େ͖͍ͱ൑அͨ͠ɻ ʢ·ͣ1SPUPˠ(SBQI2-ͷ໰୊ղܾʹूத͍ͨ͠ͷͰɺ ଞͷ໰୊Λ૿΍͢ͷΛආ͚͍ͨͱ͍͏ͷ΋͋Δʣ
  16. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2- ؔ࿈ͷఆٛʢάϥϑͷߏஙʣ GraphQL Protobuf Generate message Post

    { // ... // Required. 投稿したユーザの ID。 uint64 author_id = 11; } type Post { # ... # Required. 投稿したユーザの ID。 authorId: String! } Protobuf message User { // ... } GraphQL type User { # ... } Generate
  17. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2- ؔ࿈ͷఆٛʢάϥϑͷߏஙʣ GraphQL Protobuf Generate message Post

    { // ... // Required. 投稿したユーザの ID。 uint64 author_id = 11; } type Post { # ... # Required. 投稿したユーザの ID。 authorId: String! } Protobuf message User { // ... } GraphQL type User { # ... } Generate GraphQL extend type Post { # 投稿したユーザ author: User } ΦϒδΣΫτͷؔ࿈͸ (SBQI2-(BUFXBZଆͰఆٛ
  18. ©2021 Wantedly, Inc. 1SPUPCVG(SBQI2-/FYVT GraphQL Nexus /FYVTͰ͸FYUFOE5ZQFͰܕͷ֦ு͕Մೳ ͜͜Ͱؔ࿈Λද͢ϑΟʔϧυΛఆٛ͠ɺ SFTPMWFSʹσʔλऔಘΛ࣮૷͢Δ ؔ࿈ͷఆٛʢάϥϑͷߏஙʣ

    const addAuthorToPost = extendType({ type: "Post", definition(t) { t.field("author", { type: nullable("User"), resolver(root, _args, ctx, _info) { // root.getAuthorId() から Author 取得 // ctx から gRPC クライアントを取り出して RPC 叩く // DataLoader を使うことも多い } }); } });
  19. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. ࡞Βͳ͍ͱ͍͚ͳ͍ߟ͑ͳ͍ͱ͍͚ͳ͍΋ͷ 1SPUP͔Β(SBQI2-ͷܕΛͲ͏΍ͬͯੜ੒͢Δ͔ ˠม׵ͷϧʔϧͱɺͦͷ࣮૷Ͱ͋Δίʔυੜ੒πʔϧΛࣗ࡞ 1SPUP͔Βͷσʔλू໿ɾάϥϑߏஙΛͲ͏ఆٛɾهड़͢Δ͔ ˠ(BUFXBZͷίʔυ্Ͱ4DIFNBΛFYUFOE͠

    σʔλऔಘΛ࣮૷ 
 ʢ4JOHMF4DIFNB(BUFXBZ1BUUFSOʣ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ ෳ਺ϚΠΫϩαʔϏε͔ΒσʔλΛू໿͢Δ(SBQI2-αʔόΛ࡞Γɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ
  20. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. ࡞Βͳ͍ͱ͍͚ͳ͍ߟ͑ͳ͍ͱ͍͚ͳ͍΋ͷ 1SPUP͔Β(SBQI2-ͷܕΛͲ͏΍ͬͯੜ੒͢Δ͔ ˠม׵ͷϧʔϧͱɺͦͷ࣮૷Ͱ͋Δίʔυੜ੒πʔϧΛࣗ࡞ 1SPUP͔Βͷσʔλू໿ɾάϥϑߏஙΛͲ͏ఆٛɾهड़͢Δ͔ ˠ(BUFXBZͷίʔυ্Ͱ4DIFNBΛFYUFOE͠

    σʔλऔಘΛ࣮૷ 
 ʢ4JOHMF4DIFNB(BUFXBZ1BUUFSOʣ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ ෳ਺ϚΠΫϩαʔϏε͔ΒσʔλΛू໿͢Δ(SBQI2-αʔόΛ࡞Γɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ ✅ ✅
  21. ϖʔδλΠτϧ ϖʔδαϒλΠτϧ ©2021 Wantedly, Inc. QSPUP͔Β(SBQI2-ͷܕΛੜ੒͠ɺ ෳ਺ϚΠΫϩαʔϏε͔ΒσʔλΛू໿͢Δ(SBQI2-αʔόΛ࡞Γɺ 8FCϑϩϯτɺϞόΠϧ͔Βར༻Ͱ͖Ε͹ɺ 1SPUPCVGΛࡴͣ͞(SBQI2-΋׆͖ΔͷͰ͸ʁ 8BOUFEMZʹ͓͚Δ(SBQI2-ӡ༻্ͷ՝୊

    QSPUP্ͷ஌ࣝ(SBQI2-ʹಉظ͞Εͳ͍ ˠಉظ͞ΕΔΑ͏ʹͳͬͨ✅ ϑϩϯτΤϯυΤϯδχΞ͕QSPUPΛࢀর͠ʹ͍͘ྗֶ͸ಇ͔ͳ͍ ˠʢ8FCϑϩϯτɺϞόΠϧ͕(SBQI2-Λར༻͢Ε͹ʣಁաతʹࢀর͞ΕΔ͜ͱʹͳΔ✅
  22. ©2021 Wantedly, Inc. ΈΜͳͰҭͯΔ(SBQI2-εΩʔϚ ͦΕΛࢧ͑Δ1SPUPCVG όοΫΤϯυɾ8FCϑϩϯτɾϞόΠϧͷ։ൃऀ͕ 
 ΈΜͳಉҰͷ(SBQI2-εΩʔϚΛݟͯ։ൃ͢ΔΑ͏ʹͳΔ ˠΈΜͳ͕εΩʔϚɾυΩϡϝϯτͷվળʹؔΘΔϞνϕ͕Ͱ͖Δʂ 

    (SBQI2-εΩʔϚ͸େ෦෼͸1SPUPCVG*%-͔Βੜ੒͞ΕΔ  1SPUPCVG͸௨ৗͷϓϩάϥϛϯάݴޠͷߏ଄ମఆٛʹ͍ۙϝϯλϧϞσϧͰ ಡΈॻ͖͕Ͱ͖Δ ˠεΩʔϚ͕એݴతʹ؅ཧͰ͖ɺͦͷߋ৽ʹಛผͳ஌ࣝ΋ཁٻ͞Εͳ͍ʂ
  23. ©2021 Wantedly, Inc. ·ͱΊ ΈΜͳͰҭͯΔ(SBQI2-εΩʔϚ ͦΕΛࢧ͑Δ1SPUPCVG ‣ όοΫΤϯυͰར༻͍ͯͨ͠ࢿ࢈ʢ1SPUPCVGʣΛ׆͔ͭͭ͠ɺ(SBQI2-ͷϝϦοτ΋ڗड͍ͨ͠  (SBQI2-ͷϝϦοτಛʹ࠶ར༻ՄೳͳΦϒδΣΫτάϥϑͷߏங

    ͦͷଞ͍Ζ͍Ζ  ͦͷͨΊʹɺͭͷ໰୊ʹऔΓ૊Μͩ ‣ QSPUP͔Β(SBQI2-ͷܕΛੜ੒͍ͨ͠  ੜ੒͢Δ࢓༷Λఆٛ͠ɺ(SBQI2-/FYVTͷίʔυΛੜ੒͢Δ࣮૷Λ࡞ͬͨ ‣ 1SPUP͔Βͷσʔλू໿ɾάϥϑߏஙΛͲ͏ఆٛɾهड़͢Δ͔  4JOHMF4DIFNB(BUFXBZΞʔΩςΫνϟΛ࠾༻ͨ͠  (SBQI2-ͷAFYFOEAͷ࢓૊ΈΛར༻͠ɺ1SPUP͔Βੜ੒ͨ͠(SBQI2-0CKFDUͷάϥϑΛఆٛ͢Δ ‣ 1SPUPCVG͔Β࠶ར༻ՄೳͳΦϒδΣΫτάϥϑͱͯ͠ͷ(SBQI2-TDIFNB͕Ͱ͖ͨ  8FCϑϩϯτɾϞόΠϧΤϯδχΞͱڞ௨ݴޠͱͯ͠ར༻͢Δ͜ͱͰɺΈΜͳͰεΩʔϚΛҭͯΒΕΔ؀ڥͱͳ͍ͬͯ͘