概要
原著者の許諾を得て翻訳・公開いたします。
- 英語記事: I don't use nil - Write it simple
- 原文公開日: 2020/10/03
- 著者: Juan Manuel Ramallo
私はnilを使わない(翻訳)
私はnil
を使いません。あるいは少なくとも使わないよう努めています。
NoMethodError: undefined method 'some_method' for nil:NilClass
上はproductionシステムで実によく見かけるエラーのひとつです。このエラーは、null値を参照可能な変数ならどこでも発生する可能性があります。本記事ではこのトピックについていくつかのケーススタディを述べます。
⚓ マイグレーション
私がテーブルを作成または更新するときには、常にnull: false
制約とデフォルト値の追加を検討するようにしています。文字列値の場合デフォルトは空文字列に、数値の場合はデフォルト値はゼロにします。
こうすることでデータベースレベルでチェックされるようになり、カラムがnil
になる心配なしに操作できるようになります。たとえば、ブログシステムで以下のPost
モデルを例に考えてみましょう。
# db/migrate/...
class CreatePosts < ActiveRecord::Migration[6.0]
def change
create_table :posts do |t|
# [snip]
# 悪くない
t.string :excerpt
# さらによい
t.string :excerpt, null: false, default: ''
end
end
end
# app/views/posts/show.html.erb
<p>
<%= @post.excerpt.downcase %>
</p>
特にこのコード例では、値が常にStringオブジェクトを返すようになっているので、Post#excerpt
にdowncase
を送信すると常に通ってしまいます。
⚓ enum
次に、任意のpostが何らかのカテゴリを持てるとしましょう。これらのカテゴリはそれ以外の情報や振る舞いを持たないので、Postモデルでenum属性を使うことにします。
# db/migrate/...
class CreatePosts < ActiveRecord::Migration[6.0]
def change
create_table :posts do |t|
# [snip]
# 悪くない
t.integer :category
# さらによい
t.integer :category, null: false, default: 0
end
end
end
ここで、デフォルトのenumオプションを追加すれば簡単に「カテゴリなしのpost」を表現できます。そうする方がよい理由とは何でしょうか?Post#category
メソッドが返すオブジェクトの型が常に同じになるからです。こうすることで、カテゴリを扱う場合にコードでのnil
チェックが回避されますし、この属性を扱うときのぼっち演算子(safe navigation operator)が不要になります。
# app/models/post.rb
class Post < ApplicationRecord
enum category: { general: 0, lifestlye: 1, art: 2, misc: 3 }
end
上のコード例では、デフォルト値としてgeneral
というカテゴリが用いられます。
⚓ NullObject
NullObjectによるアプローチはnull値をエレガントに表現できます。この方法はある意味で上のenumのケーススタディと似ています。このパターンについてはthoughtbotの良記事があります。
⚓ 「エラー: nil:NilClass
にはconclusion
メソッドが定義されていません」
記事のまとめです。私がnil
を使わない理由は、プログラムでNoMethodError
エラーをraiseして欲しくないからです。これを回避するのは、コードベースでnull値を扱わないようにするのと同じぐらい簡単です。
最後に、nil
の発明者であるTony Hoareの言葉を引用します。
私が「数十億ドルの過ち」と呼んでいるのは、1965年に発明されたnull参照です。当時のわたしは、とあるオブジェクト指向言語(ALGOL W)で最初の総合的な参照用型システムを設計していました。そのときの目標は、コンパイラによる自動チェックを用いて、あらゆる参照の利用を絶対的に安全にすることでした。しかし私はnull参照を導入する誘惑に勝てませんでした。実装があまりにも容易だったからです。そしてnull参照はおびただしい数のエラー、脆弱性、システムクラッシュを呼び込み、この40年間で数十億ドルに相当するつらみや損害を引き起こしました。
Null References: The Billion Dollar Mistakeからの原著者による引用文の大意