Battle Conference U30 での登壇資料です。
自己紹介
だれこれ
- Masataka Kuwabara(pocke)
- こないだ23歳になりました
- Actcat Inc. Engineer
- Ruby / RuboCop
- 今日は 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
実装するための情報も豊富
日本語の情報も充実しています
何かあったら 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 を整えるのは難しくない
ご清聴ありがとうございました。