Consider pluggable CLI tool implementation #gocon

Consider pluggable CLI tool implementation #gocon

9eed44f137609e6ce3b6f1e14f80b9e1?s=128

Masayuki Izumi

November 25, 2018
Tweet

Transcript

  1. 1 Consider pluggable CLI tool implementation Go Conference 2018 Autumn

    - @izumin5210
  2. 2

  3. 3 grapi1SFTFOUFEPO(P$PO4QpOH https://speakerdeck.com/izumin5210/grapi-bulding-json-api-server-with-grpc-gateway-for-microservices

  4. grapi (Pͷ"1*TFSWFS։ൃମݧΛߴΊΔ$-* QBDLBHF 4 * https://github.com/izumin5210/grapi ** https://cloud.google.com/apis/design/

  5. grapi (Pͷ"1*TFSWFS։ൃମݧΛߴΊΔ$-* QBDLBHF 4 * https://github.com/izumin5210/grapi ** https://cloud.google.com/apis/design/

  6. ‣ ϘΠϥϓϨʔτͷTDBGGPMEJOH  ن໿ʹଇͬͨΠϯλϑΣʔεʢQSPUPʣͱ࣮૷ʢHPʣͷςϯϓϨʔτੜ੒  (PPHMF"1*%FTJHO(VJEF ʹԊͬͨ΋ͷ͕ੜ੒͞ΕΔ grapi (Pͷ"1*TFSWFS։ൃମݧΛߴΊΔ$-* QBDLBHF

    4 * https://github.com/izumin5210/grapi ** https://cloud.google.com/apis/design/
  7. ‣ ϘΠϥϓϨʔτͷTDBGGPMEJOH  ن໿ʹଇͬͨΠϯλϑΣʔεʢQSPUPʣͱ࣮૷ʢHPʣͷςϯϓϨʔτੜ੒  (PPHMF"1*%FTJHO(VJEF ʹԊͬͨ΋ͷ͕ੜ੒͞ΕΔ ‣ H31$*%- DPEFHFOFSBUJPO

     SPVUJOH  VO NBSTIBMJOHͳͲؾʹ͠ͳͯ͘ྑ͍ɼ
 ຊ࣭ʹϑΥʔΧε͠΍͍͢։ൃମݧΛఏڙ  HSQDHBUFXBZΛ಺แ͠ɼ;ͭ͏ͷ+40/"1*TFSWFSͱͯ͠ར༻Մ  ΋ͪΖΜɼHBUFXBZͳ͠ͷH31$TFSWFSʹ΋Ͱ͖Δ grapi (Pͷ"1*TFSWFS։ൃମݧΛߴΊΔ$-* QBDLBHF 4 * https://github.com/izumin5210/grapi ** https://cloud.google.com/apis/design/
  8. ‣ ϘΠϥϓϨʔτͷTDBGGPMEJOH  ن໿ʹଇͬͨΠϯλϑΣʔεʢQSPUPʣͱ࣮૷ʢHPʣͷςϯϓϨʔτੜ੒  (PPHMF"1*%FTJHO(VJEFʹԊͬͨ΋ͷ͕ੜ੒͞ΕΔ ‣ H31$*%- DPEFHFOFSBUJPO 

    SPVUJOH  VO NBSTIBMJOHͳͲؾʹ͠ͳͯ͘ྑ͍ɼ
 ຊ࣭ʹϑΥʔΧε͠΍͍͢։ൃମݧΛఏڙ  HSQDHBUFXBZΛ಺แ͠ɼ;ͭ͏ͷ+40/"1*TFSWFSͱͯ͠ར༻Մ  ΋ͪΖΜɼHBUFXBZͳ͠ͷH31$TFSWFSʹ΋Ͱ͖Δ grapi(Pͷ"1*TFSWFS։ൃମݧΛߴΊΔ$-* QBDLBHF 5 HSBQJʹ৽ͨͳDPEFHFOFSBUPSΛೖΕͨ͘ͳͬͨ ͔ͦ͠͠Ε͸QSPUPCVG͸͔ͭ͏͚ͲH31$͸ͪΐͬͱؔ܎ͳ͍ ୯७ͳ8FCαʔό։ൃʹؔΘͬͯ͘Δ࿩Ͱ΋ͳ͍ HSBQJ͸PQFOͳ෺ͳͷͰɼ͋·Γϔϯͳ΋ͷ͸ೖΕͨ͘ͳ͍ʜ
  9. ‣ ϘΠϥϓϨʔτͷTDBGGPMEJOH  ن໿ʹଇͬͨΠϯλϑΣʔεʢQSPUPʣͱ࣮૷ʢHPʣͷςϯϓϨʔτੜ੒  (PPHMF"1*%FTJHO(VJEFʹԊͬͨ΋ͷ͕ੜ੒͞ΕΔ ‣ H31$*%- DPEFHFOFSBUJPO 

    SPVUJOH  VO NBSTIBMJOHͳͲؾʹ͠ͳͯ͘ྑ͍ɼ
 ຊ࣭ʹϑΥʔΧε͠΍͍͢։ൃମݧΛఏڙ  HSQDHBUFXBZΛ಺แ͠ɼ;ͭ͏ͷ+40/"1*TFSWFSͱͯ͠ར༻Մ  ΋ͪΖΜɼHBUFXBZͳ͠ͷH31$TFSWFSʹ΋Ͱ͖Δ grapi(Pͷ"1*TFSWFS։ൃମݧΛߴΊΔ$-* QBDLBHF 5 HSBQJʹ৽ͨͳDPEFHFOFSBUPSΛೖΕͨ͘ͳͬͨ ͔ͦ͠͠Ε͸QSPUPCVG͸͔ͭ͏͚ͲH31$͸ͪΐͬͱؔ܎ͳ͍ ୯७ͳ8FCαʔό։ൃʹؔΘͬͯ͘Δ࿩Ͱ΋ͳ͍ HSBQJ͸PQFOͳ෺ͳͷͰɼ͋·Γϔϯͳ΋ͷ͸ೖΕͨ͘ͳ͍ʜ
  10. 6 Consider pluggable CLI tool implementation Go Conference 2018 Autumn

    - @izumin5210
  11. 7 @izumin5210 Application Engineer, Wantedly People Wantedly, Inc.

  12. 2ͳͥQMVHJOػߏ͕ඞཁͳͷ͔

  13. 2ͳͥQMVHJOػߏ͕ඞཁͳͷ͔ "։ൃऀɾར༻ऀͲͪΒ΋)BQQZʹ͢ΔͨΊ

  14. 9 Users ͓٬༷ͷ੠ʢྫʣ  ʢ1PTUHSF42-༻πʔϧʹରͯ͠ʣ.Z42-ʹ΋ରԠͯ͠΄͍͠ʂ  ʢίʔυδΣωϨʔλʹରͯ͠ʣUFTUJGZͰςετ΋ੜ੒ͯ͠ʂ Author

  15. 9 Users ͓٬༷ͷ੠ʢྫʣ  ʢ1PTUHSF42-༻πʔϧʹରͯ͠ʣ.Z42-ʹ΋ରԠͯ͠΄͍͠ʂ  ʢίʔυδΣωϨʔλʹରͯ͠ʣUFTUJGZͰςετ΋ੜ੒ͯ͠ʂ Author Զͷ੠ʢྫʣ 

    ʢ1PTUHSF42-͔͠࢖Θ΁Μ͠ʜʣ  ʢAUFTUJOHA೿ͳͷͰϞνϕʔγϣϯ͕ͳ͍ʜʣ
  16. Users ͓٬༷ͷ੠ʢྫʣ  ʢ1PTUHSF42-༻πʔϧʹରͯ͠ʣ.Z42-ʹ΋ରԠͯ͠΄͍͠ʂ  ʢίʔυδΣωϨʔλʹରͯ͠ʣUFTUJGZͰςετ΋ੜ੒ͯ͠ʂ 10 Author ͔ͤͬ͘ݟ͚ͭͯ΋Β͑ͨͷʹʜ 

    .Z42-࢖ͬͨ͜ͱͳ͍͔Β೉͍͠ʜ  ͜͜ͰରԠͪ͠Ό͏ͱɼ΄͔ͷ%#.4΋
 αϙʔτཁٻ͕དྷͪΌ͏͔΋ʜ  044CVSOPVUͦ͠͏ 6OIBQQZ Զͷ੠ʢྫʣ  ʢ1PTUHSF42-͔͠࢖Θ΁Μ͠ʜʣ  ʢAUFTUJOHA೿ͳͷͰϞνϕʔγϣϯ͕ͳ͍ʜʣ
  17. Author Զͷ੠ʢྫʣ  ʢ1PTUHSF42-͔͠࢖Θ΁Μ͠ʜʣ  ʢAUFTUJOHA೿ͳͷͰϞνϕʔγϣϯ͕ͳ͍ʜʣ 11 Users ͔ͤͬ͘ྑ͍πʔϧʹग़ձͬͨͷʹʜ 

    ࣗ෼͕ରԠ࡞ۀͯ͠΋͍͍͚Ͳɼ
 ࡞ऀ͕.Z42-࢖Θͳ͍ͳΒෆ҆ఆ͔΋ʜ  ͔ͩΒͱ͍ͬͯࣗ෼͕ϝϯς͠ଓ͚Δͷ͔ʜʁ 6OIBQQZ ͓٬༷ͷ੠ʢྫʣ  ʢ1PTUHSF42-༻πʔϧʹରͯ͠ʣ.Z42-ʹ΋ରԠͯ͠΄͍͠ʂ  ʢίʔυδΣωϨʔλʹରͯ͠ʣUFTUJGZͰςετ΋ੜ੒ͯ͠ʂ
  18. Author Զͷ੠ʢྫʣ  ʢ1PTUHSF42-͔͠࢖Θ΁Μ͠ʜʣ  ʢAUFTUJOHA೿ͳͷͰϞνϕʔγϣϯ͕ͳ͍ʜʣ 12 Users ͓٬༷ͷ੠ʢྫʣ 

    ʢ1PTUHSF42-༻πʔϧʹରͯ͠ʣ.Z42-ʹ΋ରԠͯ͠΄͍͠ʂ  ʢίʔυδΣωϨʔλʹରͯ͠ʣUFTUJGZͰςετ΋ੜ੒ͯ͠ʂ Ϣʔβ͕֎͔Β֦ுͰ͖ΔΑ͏ʹ͢Δ  ֎ʹ੾Γग़͞Εͨ%#.4ͷESJWFSΛݺͿ  ίʔυੜ੒ͷલޙͰ֎෦ϓϩάϥϜΛݺͿ
  19. 13  ຊମΞϓϦ͸ͳΔ΂͘ബ͘อͪͭͭ  ֎͔ΒॲཧΛࠩ͠ࠐΊΔιέοτ͕͋Ε͹ྑ͍ Extensibility֦ுੑͷߴ͍πʔϧ

  20. 13  ຊମΞϓϦ͸ͳΔ΂͘ബ͘อͪͭͭ  ֎͔ΒॲཧΛࠩ͠ࠐΊΔιέοτ͕͋Ε͹ྑ͍ Extensibility֦ுੑͷߴ͍πʔϧ ‣ ϢʔβͷΞϓϦέʔγϣϯίʔυ͔Βར༻  FH42-%SJWFS

    Adatabase/sql/driver.DriverA .JEEMFXBSF Ahttp.HandlerA *OUFSDFQUPS Agrpc.*InterceptorA
  21. 13  ຊମΞϓϦ͸ͳΔ΂͘ബ͘อͪͭͭ  ֎͔ΒॲཧΛࠩ͠ࠐΊΔιέοτ͕͋Ε͹ྑ͍ Extensibility֦ுੑͷߴ͍πʔϧ ‣ ϢʔβͷΞϓϦέʔγϣϯίʔυ͔Βར༻  FH42-%SJWFS

    Adatabase/sql/driver.DriverA .JEEMFXBSF Ahttp.HandlerA *OUFSDFQUPS Agrpc.*InterceptorA ‣ طଘΞϓϦέʔγϣϯʹػೳΛ֎෇͚ͯ͠ར༻  FH1SPUPDQMVHJOT 5FSSBGPSNQSPWJEFST 3BJMTHFOFSBUPST  ࠓ೔͸ͬͪ͜ͷ࿩
  22. 14 Plugin ExperienceϓϥάΠϯͱ%FWFMPQFS&YQFSJFODF Users Plugin Developers

  23. 15 Plugin ExperienceϓϥάΠϯͱ%FWFMPQFS&YQFSJFODF ‣ ϢʔβͷυϝΠϯͱπʔϧͷSFRVJSFNFOU͕ζϨͳ͍͔  FHʮΠϯϑϥπʔϧͷϓϥάΠϯػߏʹ/PEFKT͕ඞཁʯ͸ଟ෼͠ΜͲ͍ Users Plugin Developers

  24. 15 Plugin ExperienceϓϥάΠϯͱ%FWFMPQFS&YQFSJFODF ‣ ϢʔβͷυϝΠϯͱπʔϧͷSFRVJSFNFOU͕ζϨͳ͍͔  FHʮΠϯϑϥπʔϧͷϓϥάΠϯػߏʹ/PEFKT͕ඞཁʯ͸ଟ෼͠ΜͲ͍ ‣ ෳ਺ਓϓϩδΣΫτͰ΋ར༻Ͱ͖Δ͔ 

    ʮਓʹΑͬͯ࢖ͬͯΔόʔδϣϯ͕ҟͳΔʯ͸஍ࠈ  Ϛγϯάϩʔόϧ͡Όͳͯ͘ϓϩδΣΫτϩʔΧϧʹΠϯετʔϧग़དྷͳ͍ͱμϝ Users Plugin Developers
  25. 16 Plugin ExperienceϓϥάΠϯͱ%FWFMPQFS&YQFSJFODF Users Plugin Developers ‣ ࣮૷ɾσόοά͸؆୯͔  ݩπʔϧͷίϯςΩετΛࢀরɾར༻Ͱ͖Δ͔

     ϩʔΧϧͰ࡞੒தͷ΋ͷΛ࣮πʔϧ͔Βར༻Ͱ͖Δ͔  ࣮૷ͷͨΊͷϨʔϧ͸͋Δ͔
  26. 16 Plugin ExperienceϓϥάΠϯͱ%FWFMPQFS&YQFSJFODF Users Plugin Developers ‣ ࣮૷ɾσόοά͸؆୯͔  ݩπʔϧͷίϯςΩετΛࢀরɾར༻Ͱ͖Δ͔

     ϩʔΧϧͰ࡞੒தͷ΋ͷΛ࣮πʔϧ͔Βར༻Ͱ͖Δ͔  ࣮૷ͷͨΊͷϨʔϧ͸͋Δ͔ ‣ ഑෍͸؆୯͔  FH0SHBOJ[BUJPOJOUFSOBMͳπʔϧΛOQNʹެ։͢Δͷ͸͠ΜͲ͍
  27. Pluggable tools: Real-World Examples

  28. ‣ ମݧͷྑ͍πʔϧ  3BJMT(FOFSBUPST  DSFBUFSFBDUBQQ ‣ (PͰ࣮૷͠΍ͦ͢͏ͳπʔϧ  QSPUPD

     5FSSBGPSN  LVCFDUM  42-CPJMEFS Pluggable tools3FBM8PSME&YBNQMFT 18
  29. ‣ ࣮૷͕࠷ߴʹΧϯλϯ  A3BJMT(FOFSBUPST#BTFAͷαϒΫϥεΛ࡞Δ  ͜ͷαϒΫϥε໊͕·Μ·αϒίϚϯυʹʢԼͷίʔυͳΒASBJMTHJOJUJBMJ[FSAʹͳΔʣ  ࣮ߦ͢ΔͱQVCMJDNFUIPET͕ఆٛ͞Εͨॱʹݺͼग़͞Ε͍ͯ͘ Ralis Generators*%4-Ͱهड़(FNpMFʹॻ͍ͯಋೖ

    19 * https://guides.rubyonrails.org/generators.html#creating-your-first-generator class InitializerGenerator < Rails::Generators::Base def create_initializer_file create_file "config/initializers/initializer.rb", "# Add initialization content here" end end
  30. ‣ ࣮૷͕࠷ߴʹΧϯλϯ  A3BJMT(FOFSBUPST#BTFAͷαϒΫϥεΛ࡞Δ  ͜ͷαϒΫϥε໊͕·Μ·αϒίϚϯυʹʢԼͷίʔυͳΒASBJMTHJOJUJBMJ[FSAʹͳΔʣ  ࣮ߦ͢ΔͱQVCMJDNFUIPET͕ఆٛ͞Εͨॱʹݺͼग़͞Ε͍ͯ͘ ‣ ಋೖ΋ָ

     3BJMTBQQMJDBUJPOىಈ࣌ʹಡ·ΕΕ͹0,  HFNԽͯ͠(JU)VCʹஔ͚͹ɼ(FNpMFʹॻ͚ͩ͘ Ralis Generators*%4-Ͱهड़(FNpMFʹॻ͍ͯಋೖ 19 * https://guides.rubyonrails.org/generators.html#creating-your-first-generator class InitializerGenerator < Rails::Generators::Base def create_initializer_file create_file "config/initializers/initializer.rb", "# Add initialization content here" end end
  31. ‣ ར༻͢ΔUFNQMBUFͷࠩ͠ସ͕͑؆୯  FH`npx create-react-app my-app --scripts-version=react-scripts-ts` Ͱ5ZQF4DSJQUʹͳΔ  A--script-versionA͸࠷ऴతʹAyarn

    addAʹ౤͛ࠐ·ΕΔͷͰɼ೚ҙͷOQNNPEVMFͷ໊લΛೖΕ͍͍ͯ create-react-app*͍·Ͳ͖ͷ+4FS͸webpack.config.jsॻ͔ͳ͍ΜͰ͢Αʁ<ཁग़య> 20 * https://github.com/facebook/create-react-app
  32. ‣ ར༻͢ΔUFNQMBUFͷࠩ͠ସ͕͑؆୯  FH`npx create-react-app my-app --scripts-version=react-scripts-ts` Ͱ5ZQF4DSJQUʹͳΔ  A--script-versionA͸࠷ऴతʹAyarn

    addAʹ౤͛ࠐ·ΕΔͷͰɼ೚ҙͷOQNNPEVMFͷ໊લΛೖΕ͍͍ͯ ‣ ಠࣗͷUFNQMBUF΋؆୯ʹ࡞ΕΔ  ಺෦తʹ͸ASFBDUTDSJQUTAͷAscripts/init.jsAΛ࣮ߦͯ͠Δ͚ͩ  ͳͷͰɼʮΦϦδφϧͷASFBDUTDSJQUTAͷJOJUΛ࣮ߦͨ͋͠ͱʹಠࣗͷॲཧΛՃ͑ΔʯΑ͏ͳ
 Areact-scripts-<your_module_name>AΛ࡞Ε͹ྑ͍  AZBSOBEEA͕ղऍͰ͖Ε͹͍͍ͷͰɼͱΓ͋͑ͣ(JU)VCʹஔ͍ͱ͚͹ΈΜͳ࢖͑ΔʢͨͿΜʣ create-react-app*͍·Ͳ͖ͷ+4FS͸webpack.config.jsॻ͔ͳ͍ΜͰ͢Αʁ<ཁग़య> 20 * https://github.com/facebook/create-react-app
  33. create-react-app*͍·Ͳ͖ͷ+4FS͸webpack.config.jsॻ͔ͳ͍ΜͰ͢Αʁ<ཁग़య> 21 https://github.com/facebook/create-react-app/blob/v2.1.1/packages/create-react-app/createReactApp.js#L305-L313 if (useYarn) { command = 'yarnpkg'; args

    = ['add', '--exact']; // snip. [].push.apply(args, dependencies); args.push('--cwd'); args.push(root); // snip. } else { // snip. } if (verbose) { args.push('--verbose'); } const child = spawn(command, args, { stdio: 'inherit' }); child.on('close', code => { // snip. });
  34. ‣ ࣮૷͸TJNQMF FBTZ   Aprotoc --foo_out=DIR input.protoAͰAprotoc-gen-fooAͱ͍͏࣮ߦϑΝΠϧΛݺͼग़͢  Ҿ਺ͷ౉͠ํ͸ಠಛ

     ର৅ʹͳͬͯΔ QSPUPͳͲ͸TUEJO͔Β  ͦͷଞͷҾ਺͸A--foo_out=<args>:DIRAͱ͢Ε͹ʢͨͩͷจࣈྻͱͯ͠ʣ౉ͬͯ͘Δ protoc*࣮ߦ࣌ͷҾ਺೉֮ͯ͑͘͠ΒΕ΁Μ 22 * https://developers.google.com/protocol-buffers/docs/reference/go-generated
  35. ‣ ࣮૷͸TJNQMF FBTZ   Aprotoc --foo_out=DIR input.protoAͰAprotoc-gen-fooAͱ͍͏࣮ߦϑΝΠϧΛݺͼग़͢  Ҿ਺ͷ౉͠ํ͸ಠಛ

     ର৅ʹͳͬͯΔ QSPUPͳͲ͸TUEJO͔Β  ͦͷଞͷҾ਺͸A--foo_out=<args>:DIRAͱ͢Ε͹ʢͨͩͷจࣈྻͱͯ͠ʣ౉ͬͯ͘Δ ‣ ಋೖ͸ʜ  FYFDVUBCMF͔ͭA1"5)Aʹଘࡏ͢ΔPSA--plugin=path/to/protoc-gen-fooAΛ౉ͤ͹ྑ͍  ͲͷݴޠͷίϯςΩετԽʹΑͬͯಋೖ೉қ౓͕มΘΓͦ͏ protoc*࣮ߦ࣌ͷҾ਺೉֮ͯ͑͘͠ΒΕ΁Μ 22 * https://developers.google.com/protocol-buffers/docs/reference/go-generated
  36. ‣ ࣮૷͸&BTZ  ϨʔϧΛෑ͍ͯ͘Ε͍ͯΔʢAgithub.com/hashicorp/terraform/pluginAʣ  ಺෦͸Agithub.com/hashicorp/go-pluginA  ϓϥάΠϯ͕αʔόɾຊମ͕ΫϥΠΞϯτʹͳͬͯnet/rpcͰ௨৴ Terraform*͔͜͜ΒΑ͏΍͘(Pͷ࿩Ͱ͢ 23

    * https://www.terraform.io/docs/plugins/basics.html
  37. ‣ ࣮૷͸&BTZ  ϨʔϧΛෑ͍ͯ͘Ε͍ͯΔʢAgithub.com/hashicorp/terraform/pluginAʣ  ಺෦͸Agithub.com/hashicorp/go-pluginA  ϓϥάΠϯ͕αʔόɾຊମ͕ΫϥΠΞϯτʹͳͬͯnet/rpcͰ௨৴ ‣ ಋೖ͸·͋·͋

     ಛఆͷσΟϨΫτϦʹFYFDVUBCMFͳ΋ͷΛஔ͚ͩ͘  ஔ͖৔͸ϚγϯશମͰͭͳͷͰɼϓϩδΣΫτ͝ͱʹόʔδϣϯม͑Δͱ͔͸Ͱ͖ͳ͍  ʢ5FSSBGPSNͷ৔߹͸ͦΜͳधཁ΋ͳ͍ͷ͔΋ʣ Terraform*͔͜͜ΒΑ͏΍͘(Pͷ࿩Ͱ͢ 23 * https://www.terraform.io/docs/plugins/basics.html
  38. ‣ ࣮૷͸TJNQMF FBTZ   Akubectl foo barAͰAkubectl-foo-barAΛ୳࣮ͯ͠ߦ͢Δ  ίϯςΩετͱ͔͸؀ڥม਺ʹೖ͍ͬͯΔ

     (PͰ͋Ε͹ศརύοέʔδ͕ଘࡏ͢ΔʢAk8s.io/kubectl/pkg/pluginutilsA Ak8s.io/cli-runtimeAʣ kubectl*ਅͬ౰Ͱࣗવͳ΍Γํ 24 * https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/ https://github.com/kubernetes/kubernetes/blob/v1.12.2/pkg/kubectl/cmd/cmd.go
  39. ‣ ࣮૷͸TJNQMF FBTZ   Akubectl foo barAͰAkubectl-foo-barAΛ୳࣮ͯ͠ߦ͢Δ  ίϯςΩετͱ͔͸؀ڥม਺ʹೖ͍ͬͯΔ

     (PͰ͋Ε͹ศརύοέʔδ͕ଘࡏ͢ΔʢAk8s.io/kubectl/pkg/pluginutilsA Ak8s.io/cli-runtimeAʣ ‣ ಋೖ͸·͋·ָ͋ͦ͏  &YFDVUBCMFͳϑΝΠϧஔ͚ͩ͘  ͭ͘Δͱ͖͸มͳϥϯλΠϜʹґଘͤ͞ͳ͍΄͏͕਌੾ kubectl*ਅͬ౰Ͱࣗવͳ΍Γํ 24 * https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/ https://github.com/kubernetes/kubernetes/blob/v1.12.2/pkg/kubectl/cmd/cmd.go
  40. 25 type defaultPluginHandler struct{} func (h *defaultPluginHandler) Execute(executablePath string, cmdArgs,

    environment []string) error { return syscall.Exec(executablePath, cmdArgs, environment) } func handleEndpointExtensions(pluginHandler PluginHandler, cmdArgs []string) error { remainingArgs := []string{} // all "non-flag" arguments for idx := range cmdArgs { if strings.HasPrefix(cmdArgs[idx], "-") { break } remainingArgs = append(remainingArgs, strings.Replace(cmdArgs[idx], "-", "_", -1)) } foundBinaryPath := "" for len(remainingArgs) > 0 { path, err := pluginHandler.Lookup(fmt.Sprintf("kubectl-%s", strings.Join(remainingArgs, "-"))) // snip. foundBinaryPath = path break } // snip. if err := pluginHandler.Execute(foundBinaryPath, append([]string{foundBinaryPath}, cmdArgs[len(remainingArgs):]...), os.Environ()); err != nil { return err } return nil } ࣮૷͸ૉ๿ https://github.com/kubernetes/kubernetes/blob/v1.12.2/pkg/kubectl/cmd/cmd.go
  41. SQLBoiler*๻͸͜Ε͕Ұ൪޷͖Ͱ͢ 26 * https://github.com/volatiletech/sqlboiler users, err := models.Users( qm.Where("age >

    ?", 30), qm.Limit(5), qm.Offset(6), ).All(db, ctx)
  42. ‣ 8IBUJT42-#PJMFS   ίʔυੜ੒ϕʔεͷ03.  %#ͷεΩʔϚΛಡΜͰɼͦΕͬΆ͍TUSVDUͱ࣮૷Λੜ੒ͯ͘͠ΕΔ SQLBoiler*๻͸͜Ε͕Ұ൪޷͖Ͱ͢ 26 *

    https://github.com/volatiletech/sqlboiler users, err := models.Users( qm.Where("age > ?", 30), qm.Limit(5), qm.Offset(6), ).All(db, ctx)
  43. ‣ 8IBUJT42-#PJMFS   ίʔυੜ੒ϕʔεͷ03.  %#ͷεΩʔϚΛಡΜͰɼͦΕͬΆ͍TUSVDUͱ࣮૷Λੜ੒ͯ͘͠ΕΔ ‣ Ͳ͕͜QMVHHBCMFʹͳͬͯΔʁ 

    ཪͷ%#.4ʹͭͳ͍ͰɼεΩʔϚಡΜͰɼϑΝΠϧΛੜ੒͢Δ΍ͭ SQLBoiler*๻͸͜Ε͕Ұ൪޷͖Ͱ͢ 26 * https://github.com/volatiletech/sqlboiler users, err := models.Users( qm.Where("age > ?", 30), qm.Limit(5), qm.Offset(6), ).All(db, ctx)
  44. ‣ ࣮૷͕&BTZ  ATRMCPJMFS AͳFYFDVUBCMFͳϑΝΠϧΛಡΉ  ATRMCPJMEFSESJWFST*OUFSGBDFAͷ࣮૷Λ
 AESJWFST%SJWFS.BJOAʹ౉͚ͩ͢ SQLBoiler*๻͸͜Ε͕Ұ൪޷͖Ͱ͢ 27

    * https://github.com/volatiletech/sqlboiler func main() { drivers.DriverMain(&driver.PostgresDriver{}) } // Interface abstracts either a side-effect imp // that is called in order to produce the data type Interface interface { // Assemble the database information into a n Assemble(config Config) (*DBInfo, error) // Templates to add/replace for generation Templates() (map[string]string, error) // Imports to merge for generation Imports() (importers.Collection, error) }
  45. ‣ ࣮૷͕&BTZ  ATRMCPJMFS AͳFYFDVUBCMFͳϑΝΠϧΛಡΉ  ATRMCPJMEFSESJWFST*OUFSGBDFAͷ࣮૷Λ
 AESJWFST%SJWFS.BJOAʹ౉͚ͩ͢ ‣ ಋೖ͸ʁ

     A1"5)AʹFYFDVUBCMFͳϑΝΠϧΛ഑ஔ͢ΔγϦʔζ  %SJWFS΋(PQBDLBHFͳͷͰɼͱΓ͋͑ͣAHPHFUAͰ͍͍  όʔδϣϯݻఆ͸ʜ  (Pʹ΋UPPMΛϓϩδΣΫτ͝ͱʹ؅ཧ͢Δखஈ͕΄͍͠Ͱ͢Ͷ SQLBoiler*๻͸͜Ε͕Ұ൪޷͖Ͱ͢ 27 * https://github.com/volatiletech/sqlboiler func main() { drivers.DriverMain(&driver.PostgresDriver{}) } // Interface abstracts either a side-effect imp // that is called in order to produce the data type Interface interface { // Assemble the database information into a n Assemble(config Config) (*DBInfo, error) // Templates to add/replace for generation Templates() (map[string]string, error) // Imports to merge for generation Imports() (importers.Collection, error) }
  46. ‣ ମݧͷྑ͍πʔϧ  3BJMT(FOFSBUPST3VCZ΍͹͍  DSFBUFSFBDUBQQͺͬͱݟ࣏҆ΘΔ͍͚Ͳɼ69ͱ֦ுੑͷόϥϯε͸ૉ੖Β͍͠ ‣ (PͰ࣮૷͠΍ͦ͢͏ͳπʔϧ  QSPUPD

    LVCFDUMΘ͔Γ΍͍͚͢ͲϓϥάΠϯͮ͘Γ͕໘౗  5FSSBGPSNΞϓϩʔν͸͓΋͠Ζ͍͚ͲɼόʔδϣϯϩοΫ͕ඞཁͳ৔໘Ͱ೰·͍͠  42-#PJMFS(PͰUPPM؅ཧ͢Δखஈ͑͋͞Ε͹ྑͦ͞͏ʁ Pluggable tools3FBM8PSME&YBNQMFT 28
  47. Implements plugin-mechanism into grapi

  48. ‣ HSBQJͰٻΊ͍ͨཁ݅  1MVHJO͕(PͰ͋Δඞཁੑ͸ͳ͍  ͕ɼͳΜΒ͔ͷQBDLBHFNBOBHFSʹ৐͔ͬͬͨ΄͏͕࣮૷͸ָ  HSBQJ͕࣋ͬͯΔQSPUPD࣮ߦػೳ͸ར༻͍ͨ͠  ಋೖʹ಄Λ࢖Θͳ͍ͱ͍͚ͳ͍ͷ͸ආ͚͍ͨ

     όʔδϣϯϩοΫ͸ඞਢ Approach)PXUPJNQMFNFOUQMVHJONFDIBOJTJOUPHSBQJ 30
  49. ‣ HSBQJͰٻΊ͍ͨཁ݅  1MVHJO͕(PͰ͋Δඞཁੑ͸ͳ͍  ͕ɼͳΜΒ͔ͷQBDLBHFNBOBHFSʹ৐͔ͬͬͨ΄͏͕࣮૷͸ָ  HSBQJ͕࣋ͬͯΔQSPUPD࣮ߦػೳ͸ར༻͍ͨ͠  ಋೖʹ಄Λ࢖Θͳ͍ͱ͍͚ͳ͍ͷ͸ආ͚͍ͨ

     όʔδϣϯϩοΫ͸ඞਢ Approach)PXUPJNQMFNFOUQMVHJONFDIBOJTJOUPHSBQJ 31  ݁ہ(PͰ΍Δલఏͩͱָͦ͏  42-#PJMFSͱಉ͡Α͏ͳ
 )FMQFSΛ༻ҙͯ͋͛͠Δ
  50. ‣ HSBQJͰٻΊ͍ͨཁ݅  1MVHJO͕(PͰ͋Δඞཁੑ͸ͳ͍  ͕ɼͳΜΒ͔ͷQBDLBHFNBOBHFSʹ৐͔ͬͬͨ΄͏͕࣮૷͸ָ  HSBQJ͕࣋ͬͯΔQSPUPD࣮ߦػೳ͸ར༻͍ͨ͠  ಋೖʹ಄Λ࢖Θͳ͍ͱ͍͚ͳ͍ͷ͸ආ͚͍ͨ

     όʔδϣϯϩοΫ͸ඞਢ Approach)PXUPJNQMFNFOUQMVHJONFDIBOJTJOUPHSBQJ 32 πʔϧͷύοέʔδΛWFOEPSJOHͯ͠ɼ
 ͦΕΛ؅ཧɾϏϧυͰ͖Δ࢓૊Έ͕͋Δͱྑͦ͞͏
  51. 5PPMEFQFOEFODJFTΛ؅ཧɾ࣮ߦ͢Δπʔϧ github.com/izumin5210/gex5IFJNQMFNFOUBUJPOPGDMBSJGZCFTUQSBDUJDFGPSUPPMEFQFOEFODJFT 33 // Code generated by github.com/izumin5210/gex. DO NOT

    E // +build tools package tools // tool dependencies import ( _ "github.com/haya14busa/reviewdog/cmd/reviewdog" _ "github.com/srvc/wraperr/cmd/wraperr" _ "golang.org/x/lint/golint" )
  52. 5PPMEFQFOEFODJFTΛ؅ཧɾ࣮ߦ͢Δπʔϧ  ಺෦తʹ͸AEFQAAHPNPEA͍ͣΕ͔Λར༻͍ͯ͠Δ  ͷͰɼͨͩ͘͠όʔδϣϯϩοΫ͞ΕΔ github.com/izumin5210/gex5IFJNQMFNFOUBUJPOPGDMBSJGZCFTUQSBDUJDFGPSUPPMEFQFOEFODJFT 33 // Code generated

    by github.com/izumin5210/gex. DO NOT E // +build tools package tools // tool dependencies import ( _ "github.com/haya14busa/reviewdog/cmd/reviewdog" _ "github.com/srvc/wraperr/cmd/wraperr" _ "golang.org/x/lint/golint" )
  53. 5PPMEFQFOEFODJFTΛ؅ཧɾ࣮ߦ͢Δπʔϧ  ಺෦తʹ͸AEFQAAHPNPEA͍ͣΕ͔Λར༻͍ͯ͠Δ  ͷͰɼͨͩ͘͠όʔδϣϯϩοΫ͞ΕΔ  AUPPMTHPAͱ͍͏ϑΝΠϧΛੜ੒ͯ͠JNQPSU͍ͯ͠Δ  *NQPSUͯ͠ͳ͍ϑΝΠϧ͸؅ཧ͞Εͳ͍ͷͰ github.com/izumin5210/gex5IFJNQMFNFOUBUJPOPGDMBSJGZCFTUQSBDUJDFGPSUPPMEFQFOEFODJFT

    33 // Code generated by github.com/izumin5210/gex. DO NOT E // +build tools package tools // tool dependencies import ( _ "github.com/haya14busa/reviewdog/cmd/reviewdog" _ "github.com/srvc/wraperr/cmd/wraperr" _ "golang.org/x/lint/golint" )
  54. 5PPMEFQFOEFODJFTΛ؅ཧɾ࣮ߦ͢Δπʔϧ  ಺෦తʹ͸AEFQAAHPNPEA͍ͣΕ͔Λར༻͍ͯ͠Δ  ͷͰɼͨͩ͘͠όʔδϣϯϩοΫ͞ΕΔ  AUPPMTHPAͱ͍͏ϑΝΠϧΛੜ੒ͯ͠JNQPSU͍ͯ͠Δ  *NQPSUͯ͠ͳ͍ϑΝΠϧ͸؅ཧ͞Εͳ͍ͷͰ 

    ΋ͱ΋ͱ͸AmockgenAͷόʔδϣϯΛݻఆͨͯ͘͠࡞ͬͨ github.com/izumin5210/gex5IFJNQMFNFOUBUJPOPGDMBSJGZCFTUQSBDUJDFGPSUPPMEFQFOEFODJFT 33 // Code generated by github.com/izumin5210/gex. DO NOT E // +build tools package tools // tool dependencies import ( _ "github.com/haya14busa/reviewdog/cmd/reviewdog" _ "github.com/srvc/wraperr/cmd/wraperr" _ "golang.org/x/lint/golint" )
  55. 5PPMEFQFOEFODJFTΛ؅ཧɾ࣮ߦ͢Δπʔϧ  ಺෦తʹ͸AEFQAAHPNPEA͍ͣΕ͔Λར༻͍ͯ͠Δ  ͷͰɼͨͩ͘͠όʔδϣϯϩοΫ͞ΕΔ  AUPPMTHPAͱ͍͏ϑΝΠϧΛੜ੒ͯ͠JNQPSU͍ͯ͠Δ  *NQPSUͯ͠ͳ͍ϑΝΠϧ͸؅ཧ͞Εͳ͍ͷͰ 

    ΋ͱ΋ͱ͸AmockgenAͷόʔδϣϯΛݻఆͨͯ͘͠࡞ͬͨ  ʢ͙͢ެࣜʹ΋ೖΔͰ͠ΐʜͱ͍͏ࢥ͍͕͋ΔͷͰബ͘Ͱ͖͍ͯΔʣ github.com/izumin5210/gex5IFJNQMFNFOUBUJPOPGDMBSJGZCFTUQSBDUJDFGPSUPPMEFQFOEFODJFT 33 // Code generated by github.com/izumin5210/gex. DO NOT E // +build tools package tools // tool dependencies import ( _ "github.com/haya14busa/reviewdog/cmd/reviewdog" _ "github.com/srvc/wraperr/cmd/wraperr" _ "golang.org/x/lint/golint" )
  56. ‣ HSBQJͰٻΊ͍ͨཁ݅  1MVHJO͕(PͰ͋Δඞཁੑ͸ͳ͍  ͕ɼͳΜΒ͔ͷQBDLBHFNBOBHFSʹ৐͔ͬͬͨ΄͏͕࣮૷͸ָ  HSBQJ͕࣋ͬͯΔQSPUPD࣮ߦػೳ͸ར༻͍ͨ͠  ಋೖʹ಄Λ࢖Θͳ͍ͱ͍͚ͳ͍ͷ͸ආ͚͍ͨ

     όʔδϣϯϩοΫ͸ඞਢ Approach)PXUPJNQMFNFOUQMVHJONFDIBOJTJOUPHSBQJ 34 πʔϧͷύοέʔδΛWFOEPSJOHͯ͠ɼ
 ͦΕΛ؅ཧɾϏϧυͰ͖Δ࢓૊Έ͕͋Δͱྑͦ͞͏ ಺෦తʹHFYΛ͔ͭ͑͹Αͦ͞͏ʂ
  57. Plugin exampleHSQBJHFODPNNBOE 35

  58. Plugin exampleHSQBJHFODPNNBOE 35  γϯϓϧͳྫ

  59. Plugin exampleHSQBJHFODPNNBOE 35  γϯϓϧͳྫ  ੩తϑΝΠϧʢUFNQBMUFʣͷFNCFEEJOHʹ͸WGTHFOΛ࢖ͬͨ  ಺෦తʹ͸AIUUQ'JMF4ZTUFNAʹͳΕ͹ԿͰ΋͍͍

  60. Plugin exampleHSQBJHFODPNNBOE 35  γϯϓϧͳྫ  ੩తϑΝΠϧʢUFNQBMUFʣͷFNCFEEJOHʹ͸WGTHFOΛ࢖ͬͨ  ಺෦తʹ͸AIUUQ'JMF4ZTUFNAʹͳΕ͹ԿͰ΋͍͍ 

    ੜ੒ίʔυΛTOBQTIPUUFTU͍ͯ͠Δ - github.com/bradleyjkemp/cupaloy
  61. Plugin exampleHSQBJHFOUZQF 36

  62. Plugin exampleHSQBJHFOUZQF 36  ͪΐͬͱ͚ͩ΍΍͍͜͠ྫ  %*ͱ͔͋Δͷ͸ɼHSBQJຊମͷQSPUPD8SBQQFSΛར༻͍ͨͨ͠Ί  ຊମ͕಺෦ͰXJSFΛ࢖͍ͬͯΔͷͰɼͦΕʹ৐͔ͬͬͨ 

    ͳͷͰผʹඞਢ͡Όͳ͍
  63. Plugin exampleHSQBJHFOUZQF 37 func main() { buildCommand(di.NewApp).MustExecute() } func buildCommand(createApp

    di.CreateAppFunc, opts ...gencmd.Option) gencmd.Exec { return gencmd.New( "type", newGenerateCommand(createApp), newDestroyCommand(), opts..., ) } func newGenerateCommand(createApp di.CreateAppFunc) *gencmd.Command { var ( app *di.App
  64. Plugin exampleHSQBJHFOUZQF 38 func newGenerateCommand(createApp di.CreateAppFunc) *gencmd.Command { var (

    app *di.App ) return &gencmd.Command{ Use: "generate NAME", Short: "Generate a new type", Args: cobra.ExactArgs(1), TemplateFS: template.FS, ShouldInsideApp: true, PreRun: func(c *gencmd.Command, args []string) error { var err error app, err = createApp(c) return errors.WithStack(err) }, BuildParams: func(c *gencmd.Command, args []string) (interface{}, error) { return buildParams(args[0], c.Ctx().Ctx) }, PostRun: func(c *gencmd.Command, args []string) error { return errors.WithStack(app.Protoc.Exec(context.TODO())) }, } }
  65. Plugin exampleHSQBJHFOUZQF 39 func newGenerateCommand(createApp di.CreateAppFunc) *gencmd.Command { var (

    app *di.App ) return &gencmd.Command{ Use: "generate NAME", Short: "Generate a new type", Args: cobra.ExactArgs(1), TemplateFS: template.FS, ShouldInsideApp: true, PreRun: func(c *gencmd.Command, args []string) error { var err error app, err = createApp(c) return errors.WithStack(err) }, BuildParams: func(c *gencmd.Command, args []string) (interface{}, error) { return buildParams(args[0], c.Ctx().Ctx) }, PostRun: func(c *gencmd.Command, args []string) error { return errors.WithStack(app.Protoc.Exec(context.TODO())) }, } }  ґଘϞδϡʔϧͷॳظԽ  ͜͜Ͱ͸ࣗલͷ%*DPOUBJOFSΛ
 ࢖͍ͬͯΔ͕ɼ;ͭ͏͸Կ΋͠ͳ͍
  66. Plugin exampleHSQBJHFOUZQF 40 func newGenerateCommand(createApp di.CreateAppFunc) *gencmd.Command { var (

    app *di.App ) return &gencmd.Command{ Use: "generate NAME", Short: "Generate a new type", Args: cobra.ExactArgs(1), TemplateFS: template.FS, ShouldInsideApp: true, PreRun: func(c *gencmd.Command, args []string) error { var err error app, err = createApp(c) return errors.WithStack(err) }, BuildParams: func(c *gencmd.Command, args []string) (interface{}, error) { return buildParams(args[0], c.Ctx().Ctx) }, PostRun: func(c *gencmd.Command, args []string) error { return errors.WithStack(app.Protoc.Exec(context.TODO())) }, } }  UFYUUFNQMBUFʹ౉Δύϥϝλ૊Έཱͯ  ϑΝΠϧͷੜ੒ɾॏෳ൑ఆͳͲ͸
 উखʹ΍ͬͯ͘ΕΔ
  67. Plugin exampleHSQBJHFOUZQF 41 func newGenerateCommand(createApp di.CreateAppFunc) *gencmd.Command { var (

    app *di.App ) return &gencmd.Command{ Use: "generate NAME", Short: "Generate a new type", Args: cobra.ExactArgs(1), TemplateFS: template.FS, ShouldInsideApp: true, PreRun: func(c *gencmd.Command, args []string) error { var err error app, err = createApp(c) return errors.WithStack(err) }, BuildParams: func(c *gencmd.Command, args []string) (interface{}, error) { return buildParams(args[0], c.Ctx().Ctx) }, PostRun: func(c *gencmd.Command, args []string) error { return errors.WithStack(app.Protoc.Exec(context.TODO())) }, } }  ੜ੒ͷલޙʹ೚ҙͷॲཧΛڬΊΔ  ͜͜Ͱ͸QSPUPDΛ͍͍ײ͡ʹ
 ࣮ߦ͍ͯ͠Δ
  68. ‣ ςετ༻ͷNPDLTUVC͸༻ҙͯ͋͛͠Δ  ͓͠ΌΕඪ४ग़ྗͱ͔ɼࠓճͷ৔߹ͩͱQSPUPDͱ͔ ‣ &YBNQMFΛ༻ҙͯ͋͛͠Δ  ͜Ε͕Ұ൪ମݧྑ͘ͳΔؾ͕͢Δ  HSBQJͷ৔߹͸HFOFSBUPS͕͢΂ͯQMVHJOʹͳ͍ͬͯΔͷͰɼ͜Ε͕ͦͷ··FYBNQMFʹͳΔ

     ͨͩυΩϡϝϯτ͕ͳ͍ͷͰʜ ‣ 1MVHJOHFOFSBUPSΛఏڙ͢Δ  50%0ͭ͗ͷϦϦʔεʹؚΊΔ TipsGPSJNQSPWJOH%FWFMPQFS&YQFSJFODF 42
  69. Go Conference 2018 Autumn - @izumin5210 ConclusionΈΜͳ͕޾ͤʹͳΔπʔϧΛ࡞ΔͨΊʹ ‣ ϝΠϯ͡Όͳ͍ػೳ͸ɼQMVHJOͱͯ͠ఏڙͰ͖ΔΑ͏ʹ͢Δ 

    044CVSOPVU๷ࢭ  ܧଓతʹϝϯς͍ͯͨ͘͠Ίʹ΋ɼʮͻͱͭͷ͜ͱΛ͏·͘΍ΔʯΞʔΩςΫνϟ ‣ ࢖͍΍͍͢ɾ࡞Γ΍͍͢QMVHJOػߏ  Ϣʔβͷ஌ࣝɾπʔϧͷίϯςΩετʹ͋ͬͨखஈͰఏڙͰ͖ΔΑ͏ʹ  AHJUDMPOFA௚ޙͰ΋໰୊ͳ͘࢖͍࢝ΊΒΕΔΑ͏ʹ  ϓϥάΠϯΛ࡞Δਓ΋CVSOPVU͠ͳ͍Α͏ʹ