Slide 1

Slide 1 text

ྺ࢙తܦҢͷઆ໌ as code Code Review Meetup by Sider #4 2018/09/26 Presentation by FUJI Goro (@__gfx__)

Slide 2

Slide 2 text

ࣗݾ঺հ • id:gfx • Bit JouruneyͰKibelaΛ։ൃ͍ͯ͠Δ • Kibela: ίϥϘϨʔγϣϯπʔϧ • ࣾ಺ϒϩά & wiki ͱ͍͏SaaS • ࠷ۙͷؔ৺ࣄ͸ DX: Developer Experience

Slide 3

Slide 3 text

ίʔυϨϏϡʔͱྺ࢙తܦҢ • ίʔυϨϏϡʔ͸΍Δͱͯ͠ʮྺ࢙తͷઆ໌ʯͬͯ͋Γ·͢ΑͶ • ʮͦͷϝιου͸·ͩੜ͖ͯ·͕͢ݹ͍ͷͰ࢖Θͳ͍Ͱͩ͘͞ ͍ʯ • ʮͦͷgem͸ґଘؔ܎ͷ౎߹্࢖͑ͪΌ͍·͕͢ɺ໰୊͕͋Δ ͷͰ࢖Θͳ͍Ͱ͍ͩ͘͞ʯ • ʮͦͷgemͷ࢖͍ํͰ͕͢ɺϕετϓϥΫςΟε͸˓˓ͳͷͰ ै͍ͬͯͩ͘͞ʯ

Slide 4

Slide 4 text

ྺ࢙తܦҢͷઆ໌ as code ͱ͸ • ྺ࢙తܦҢͷઆ໌͸͍͍ͩͨύλʔϯ͕͋Δ • ϓϩδΣΫτݻ༗ͷϕετϓϥΫςΟε • ৽چ࢓༷͕ࠞࡏ͍ͯ͠Δա౉ظͷա͝͠ํ • ύλʔϯ͕͋ΔͳΒࣗಈԽ͢Ε͹͍͍͡Όͳ ͍ʂ⇢ “ྺ࢙త(ry as code”

Slide 5

Slide 5 text

ຊ೔ͷςʔϚ: Querlyʢ͑͘Γʙʣ • Querly͸ίʔυϨϏϡʔͷࣗಈԽπʔϧͳ͕ Βɺ࢖͍ํ͕গ͠Ή͔͍ͣ͠ • ͱ͍͏ΑΓɺ “Querly͕ఏڙ͢ΔՁ஋” ͕Θ͔ Γʹ͍͘ • ͦ͜ͰʮίʔυϨϏϡʔͷࣗಈԽͷͨΊʹ QuerlyΛ࢖͏ʯͱ͍͏͜ͱΛओ୊ʹ࿩͢

Slide 6

Slide 6 text

KibelaͱQuerlyͷ෇͖߹͍ • querly.ymlͷinitial commit͸ 2016೥9݄ • ࠷ॳ͸࢖͍ॴ͕͍·͍ͪཧղͰ͖ͳ͔ͬͨ • ·͡Ίʹӡ༻͠͸͡Ίͨͷ͸ 2017೥6݄ • Querly meetup ʹग़ͯΑ͏΍͘ཧղ͠͸͡ΊΔ • 2018೥ʹͳ͔ͬͯΒසൟʹϧʔϧΛߋ৽͢ΔΑ͏ʹ • 2೥ோΊͯ “ྺ࢙త(ry as code” ͱ͍͏ཧղʹ౸ୡͨ͠

Slide 7

Slide 7 text

Querly: ྺ࢙త(ry as code • ύλʔϯԽ͍ͯ͠Δ΋ͷ͸ࣗಈԽͰ͖Δ • ύλʔϯϚον⇢ܯࠂϝοηʔδͷग़ྗ ͱ͍ ͏λεΫΛ࣮ߦ͢Δͷ͕ querly(1) • QuerlyΛpull-requestͷมߋൣғʹݶఆ࣮ͯ͠ ߦͯ͘͠ΕΔSaaS͕SiderͰ͢

Slide 8

Slide 8 text

QuerlyͷϫʔΫϑϩʔ • `querly console [path…]` ͰconsoleΛ։͘ • `find $pattern` ͰύλʔϯϚον • querly.yml ʹύλʔϯͱܯࠂจΛ௥Ճ • bad pattern͕ͳ͍৔߹͸ɺ࣮ࡍʹιʔεʹॻ ͍ͯ֬ೝ͢Δ

Slide 9

Slide 9 text

Demo

Slide 10

Slide 10 text

Querly DSL • Querly͸จࣈྻʹର͢ΔύλʔϯϚονͰ͸ ͳ͘ɺRuby AST ʹରͯ͠ύλʔϯϚονΛߦ ͏ • ͜ͷύλʔϯϚον͸DSLͳͷͰֶश͕ඞཁ • ͦ͜Ͱquerly consoleͰࢼߦࡨޡ͢Δ

Slide 11

Slide 11 text

Querly DSL example (1) • foo • “foo” ͱ͍͏ϝιουݺͼग़͠ • Ҿ਺͸೚ҙ • ม਺΍จࣈྻɺγϯϘϧ͸ؚ·ͳ͍

Slide 12

Slide 12 text

Querly DSL example (2) • _ • ೚ҙͷࣜʹϚον • foo(_) ͩͱʮ೚ҙͷҾ਺Λ1͚ͭͩ༩͑Δϝ ιουݺͼग़͠ʯͱ͍͏ҙຯ

Slide 13

Slide 13 text

Querly DSL example (3) • … • ೚ҙͷҾ਺ϦετʹϚον • foo(…) ͸ foo ͱಉ͡ɺͨͩ͠ෳࡶͳύλʔ ϯΛॻ͘ͱ͖͸…ͷ໌͕ࣔඞཁͳ͜ͱ͕͋ Δ

Slide 14

Slide 14 text

Querly DSL example (4) • foo(…){} • blockΛͱΔfooͷݺͼग़͠ʹϚον • …͸ඞਢ • foo(…)!{} • blockΛͱΒͳ͍fooͷݺͼग़͠ʹϚον • …͸ඞਢ

Slide 15

Slide 15 text

Querly DSL examples (5) • [conditional], [!conditional] • `save [conditiona]` Ͱʮ#save Λ৚݅ࣜͰධ Ձ͍ͯ͠Δͱ͖ʯʹϚον • `save [!conditional]` Ͱʮ#save Λ৚݅ࣜͰ ධՁ͍ͯ͠ͳ͍ͱ͖ʯʹϚον

Slide 16

Slide 16 text

Querly DSL syntax • ৄࡉ͸ϚχϡΞϧࢀরͷ͜ͱ • https://github.com/soutaro/querly/blob/ master/manual/patterns.md

Slide 17

Slide 17 text

ࣄྫ from kibela/querly.yml

Slide 18

Slide 18 text

ϝλϓϩͷ཈੍ - id: sample.metaprogramming_abuse pattern: - classify - constantize - eval - instance_values - safe_constantize message: "本当にメタプログラミングが必要か3回 考えてください。" ※ 3ճߟ͑ͯ΋୅Ҋ͕ͳ͍ͳΒ࢖ͬͯ΋Α͍ɻͦ͏͍͑͹ send ܥ΋͜͜ʹՃ͍͑ͨɻ

Slide 19

Slide 19 text

migration ࣌ͷΧϥϜͷ࡟আ - id: kibela.remove_column pattern: - "remove_column" - "remove_reference" message: | カラムを削除する前に、該当カラムを使わないよう にした上で `ignore_colums` で無視するようにしてく ださい。 参考文献: Rails アプリでオンラインでカラムの削 除やリネームを行うには - eagletmt's blog http:// eagletmt.hateblo.jp/entry/2017/09/24/004709

Slide 20

Slide 20 text

ARͷenumͷ࢖͍ํ - id: kibela.user_roles pattern: "User.roles[:symbol:]" message: "User.roles[:member] は多くの場合で必要 ありません。たとえばupdateやwhereではenum symbolを 使えます。" ※ ੲ͸ARͷenumͷ࢖͍ํ͕Θ͔ͬͯͳ͔ͬͨͷͰɻ࢖༻Օ ॴ͕ଟ͍͏͑ʹࣗಈͰஔ͖׵͑ΒΕΔ΄ͲͰ΋ͳ͍ͷͰա౉ ظ͸஫ҙשى͚ͩʹ͢Δ

Slide 21

Slide 21 text

localeͷࢀরͷ͔ͨ͠ - id: kibela.current_user_locale pattern: "current_user.locale" message: "current_userはログインしていない場合nil になります。 I18n.localeを使ってください。"

Slide 22

Slide 22 text

Raw SQL΁ͷ஫ҙשى - id: kibela.order_by_string pattern: - "order(:dstr:)" - "where(:dstr:)" - "find(:dstr:)" - "exists?(:dstr:)" message: "文字列によるSQL構築は本当に必要です か? SQL Injection を引き起こさないように気をつけ てください。"

Slide 23

Slide 23 text

block.callΛ͔͍ͭ·͠ΐ͏ - id: kibela.block_call pattern: - "yield" message: "yieldではなくblock.callを使いましょう。 そのほうが渡す引数が明確になります。"

Slide 24

Slide 24 text

developmentͰͷΈଘࡏ͢Δ ϝιου΁ͷ஫ҙשى - id: kibela.yard_class_name pattern: "class_name()" message: "Class#class_name は yard gem による拡 張なのでproductionでは使えません。必要なのはビルト インメソッドの Class#name ではないですか。"

Slide 25

Slide 25 text

graphql-ruby ͷϕετϓϥΫ ςΟε - id: kibela.connection_type_without_resolver pattern: "field(:symbol:, _.connection_type, ..., !resolve: _, ...)" message: "Relay connection に resolver が設定さ れていません。 AR::Relation に対するconnectionは resolver でソートを指定すべきです。” ※ʮ field(:notes, Note.connection_type) Ͱ resolver option ͕ͳ ͍ύλʔϯʯͱಡΉɻසൃ͢Δϛεͳ͕Β΋ͱ΋ͱsortͯ͋͠Δ ͜ͱ΋͋ΔͷͰgraphql-rubyຊମͰαϙʔτ͢΂͖Ͱ΋ͳ͍

Slide 26

Slide 26 text

چػೳΛ࢒ͭͭ͠ҠߦΛଅ͢ - id: kibela.accessible_for pattern: "accessible_for(_)" message: "accessible_for(user) は古いメソッドで す。 readable_by(user) または manageable_by(user) を使ってください" justification: “互換性の確認のためtestでは一部 残っています。余裕があれば新しいメソッドに書き換え てください" ※ Kibela ACL v1 ͔Β ACL v2 ʹҠߦ͢Δʹ͋ͨͬͯΞΫη εݖݶܥΛΨόͬͱม͑Δʹ͋ͨΓɺʮچϝιου͸ҰԠ࢒ ͕͢৽نίʔυͰ͸࢖༻ېࢭʯͱ͍͏͜ͱʹ͔ͨͬͨ͠

Slide 27

Slide 27 text

FAQ

Slide 28

Slide 28 text

Linter ͱ͸Կ͕ҧ͏ʁ • linter ͸ʮҰൠతͳϧʔϧʯͷνΣοΫ • ͲͷϓϩδΣΫτɾͲͷϨϏϡΞʔͰ΋ಉ͡ࢦఠ Λ͢ΔͳΒlinterͷruleΛͭ͘Δ΂͖ • Querly͸ʮϓϩδΣΫτݻ༗ͷϧʔϧʯͷνΣοΫ • ଐਓԽ͕ͪ͠ͳʮྺ࢙తܦҢʯΛίʔυԽ͢Δ΋ ͷ

Slide 29

Slide 29 text

ࢥͬͨͱ͓ΓʹϚον͠ͳ͍Αʁ • TwitterͰ࡞ऀʹฉ͘ͷ͕ૣ͍Ͱ͢ • ⇢ @soutaro • লུͰ͖ͦ͏ͳύλʔϯΛলུͰ͖ͳ͍͜ͱ ͕͋Γ·͢ (e.g. ○: `foo(…){}` , ×: `foo{}`)

Slide 30

Slide 30 text

ޡݕ஌͕ଟ͗͢ΔΜͰ͕͢ʁ • Rubyʹ͸ܕ͕ͳ͍ͷͰ͠ΐ͏͕ͳ͍ΜͰ͢ • ޡݕ஌͕ଟ͍ͱ͍͏͜ͱ͸ϝιουͷ໋໊نଇ ʹҰ؏ੑ͕ͳ͍ͷ͔΋͠Ε·ͤΜɻ໋໊نଇΛ ݟ௚͢ͳͲͯ͠Έ·͠ΐ͏ • e.g. ಠࣗʹఆٛ͢Δ update / update! ͳͲ͸ ARͱৼΔ෣͍ΛҰகͤ͞Δ

Slide 31

Slide 31 text

ଞࣾͷࣄྫΛ΋ͬͱ஌Γ͍ͨ • Θ͔Δ • ઃఆ͸ϓϩδΣΫτݻ༗ͳͷͰҰൠతʹ഑෍͢Δ΋ͷ Ͱ΋ͳ͍ • ͱ͸͍͑ൺֱతҰൠతͳϧʔϧ͸഑෍ͯ͠΋Αͦ͞͏ • `querly init` ͱ͔ͰͦΕͳΓʹ࢖͑ΔϨϕϧͷ querly.yml ͕ੜ੒͞Εͯ΄͍͠ؾ΋͢Δ

Slide 32

Slide 32 text

That’s it.