LoginSignup
50
40

More than 5 years have passed since last update.

自分の足を撃たない技術

Posted at
1 / 30

Battle Conference U30 での登壇資料です。


自己紹介


だれこれ

  • Masataka Kuwabara(pocke)
  • こないだ23歳になりました
  • Actcat Inc. Engineer
  • Ruby / RuboCop
    • 今日は Ruby での例が多くなります :gem:
  • Twitter: @p_ck_
  • GitHub: @pocke

minpocke.png


普段やってること


SideCI

自動コードレビュー

2017-03-08-213138_1198x616_scrot.png
170311124738.png


Shibart

GitHub の芝を Tシャツにする

1487946652.png
t-shirt.png


本題


今日のテーマ

  • 挑戦
    • 私が挑戦していること
    • かつ、皆さんにも挑戦していただきたいこと

私は何に挑戦しているのか

表題は「自分の足を撃たない技術」

  • 自分の足を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_ に聞けば :ok_woman:


Feature Request の Issue を作るのもアリ

  • 「こういうルールがほしい」「作ろう!:thumbsup:」のような流れもよくある
  • 気兼ねなく Issue を建てよう
    • 全世界の他のプログラマが同じバグを作らないため

でも RuboCop だけじゃうまくいかない時も…

  • バグの原因が社内特有で公開するものではない
    • 社内で定義されているメソッド起因とか
  • RuboCop に Issue / PR 出すにはハードル高い

そこで Querly!

Ruby 用の Lint ツール

soutaro/querly

  • ルールを書くのが簡単
    • 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 以外の言語の場合

選択肢は沢山ある


まとめ

  • バグを再発させない為に、Lint を整える挑戦をしよう :muscle:
    • 同じ過ちを繰り返して(自分の|世界中のプログラマの)時間を無駄にしない為に
  • Lint を整えるのは難しくない
    • Ruby なら RuboCopQuerly がオススメ
    • 他の言語でもよく使われているものを見てみよう

ご清聴ありがとうございました。

50
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
40