Battle Conference U30 での登壇資料です。
自己紹介
だれこれ
- Masataka Kuwabara(pocke)
- こないだ23歳になりました
- Actcat Inc. Engineer
- Ruby / RuboCop
- 今日は Ruby での例が多くなります 
 
- 今日は Ruby での例が多くなります 
- Twitter: @p_ck_
- GitHub: @pocke
普段やってること
SideCI
自動コードレビュー
Shibart
GitHub の芝を Tシャツにする
本題
今日のテーマ
- 挑戦
- 私が挑戦していること
- かつ、皆さんにも挑戦していただきたいこと
 
私は何に挑戦しているのか
表題は「自分の足を撃たない技術」
- 自分の足を2度撃たない技術
- バグを再発させないこと
に挑戦
突然ですが、バグを直す時何をしていますか?
バグを直す時の、よくある光景
- バグを直す
- 直っていることを確認するテストを書く
- (余力があれば)注意喚起の為にブログなどで記事を書く
これはバグの再発防止に繋がっているのか?
- テストを書く
- 該当箇所の正しさは保証される
- ただし、他の関数内 / 他のプロダクトではまた同じバグを生むかも知れない
 
- 記事を書く
- 危ないコード例を広く知らせることが出来る
- ただし、人間は忘れる生き物
- また同じ様なバグを産んでしまわないとは限らない
 
 
これらの対策のみでは不十分!
そこで Lint !
Lint とは
- プログラミング言語の静的解析ツール
- コンパイラ / インタプリタだけではチェックできない、バグの原因となるコードをチェックする
たとえば Ruby での例
バグのあるコード
Ruby では Python や算数みたいに 0 < x < 20 のように書くことが出来ない
# A Ruby program
x = 3
# NoMethodError undefined method `<' for true:TrueClass
if 0 < x < 20
  puts x
end
$ ruby tset.rb
test.rb:5:in `<main>': undefined method `<' for true:TrueClass (NoMethodError)
RuboCop を使うと
RuboCop は Ruby 用の Lint
$ rubocop
Inspecting 1 file
W
Offenses:
test.rb:5:4: W: Use the && operator to compare multiple values.
if 0 < x < 20
   ^^^^^^^^^^
1 file inspected, 1 offenses detected
0 < x < 20 ではなく 0 < x && x < 20 を使用するように指摘してくれる!
Lint のメリット
- テストと違い、全てのコードに対して適用可能
- テスト: テスト対象にしか効果がない
- Lint: テスト対象のコード以外にも、他のプロダクトのコードにも適用可能
 
- ブログを使用して情報発信した場合と違い、機械的に検査できる
- ブログ: 人間が覚えてないと意味がない
- Lint: 機械が検査するので忘れない!(CIを設定するのがオススメ)
 
ここまでは Lint を使う話
Lint を使う から 作る へ
- Lint を使うとバグを事前に防ぐことが出来る
- テスト等とは違いとても広い範囲に有効
 
- それならば、Lint のルールをみんなで書けばみんなハッピーなのでは!
作ってしまったバグをどんどん Lint のルールにしていこう!
RuboCop のルール(Cop)を書くのは意外と簡単
さっきの 0 < x < 20 を検出する RuboCop のルールの実装は結構短い
def_node_matcher :multiple_compare?, <<-PATTERN
  (send (send _ {:< :> :<= :>=} $_) {:< :> :<= :>=} _)
PATTERN
def on_send(node)
  return unless multiple_compare?(node)
  add_offense(node, :expression)
end
https://github.com/bbatsov/rubocop/blob/master/lib/rubocop/cop/lint/multiple_compare.rb
実装するための情報も豊富
日本語の情報も充実しています
何かあったら Twitter で @p_ck_ に聞けば  
Feature Request の Issue を作るのもアリ
- 「こういうルールがほしい」「作ろう!」のような流れもよくある 
- 気兼ねなく Issue を建てよう
- 全世界の他のプログラマが同じバグを作らないため
 
でも RuboCop だけじゃうまくいかない時も…
- バグの原因が社内特有で公開するものではない
- 社内で定義されているメソッド起因とか
 
- RuboCop に Issue / PR 出すにはハードル高い
そこで Querly!
Ruby 用の Lint ツール
- ルールを書くのが簡単
- YAML で定義出来る
 
- 使う人がルールを定義出来る
- ローカルルールについて検査出来る。
- RuboCop には適さない項目も検査できる!
 
 
- ローカルルールについて検査出来る。
Querly の例
例えば社内では以下のようなルールを書いています(一部抜粋)。
- id: com.sideci.oj
  pattern:
    - JSON.load
    - JSON.dump
  message: Oj を使ってください
- id: com.sideci.shallow_dig
  pattern: "dig(_)"
  before: "task.dig('id')"
  after: "task['id']"
  message: 階層が2以上でなければ、Hash#dig(_)よりもHash#[]を使ってください。
Ruby 以外の言語の場合
選択肢は沢山ある
- JavaScript: ESLint
- プラグインが活発な印象
 
- Golang: Go Meta Linter
- 沢山の Linter の Wrapper
 
- CSS: StyleLint
- などなど
まとめ
- バグを再発させない為に、Lint を整える挑戦をしよう - 同じ過ちを繰り返して(自分の|世界中のプログラマの)時間を無駄にしない為に
 
- Lint を整えるのは難しくない
ご清聴ありがとうございました。
pocke
81Contribution