はじめに
Qiitaやブログに技術記事を書く場合は多かれ少なかれ、サンプルコードを書くと思います。
たかがサンプルコード、されどサンプルコード。
技術記事に書くサンプルコードはどうあるべきなのでしょうか?
いろいろな観点があると思いますが、この記事では僕が考える「よいサンプルコード」について語ってみようと思います。
なお、この記事のサンプルコードはRubyで書いていますが、記事の内容自体はRubyに限らずどんな言語にも適用できるものです。
どういったサンプルコードが理想的なのか(大雑把なレベルで)
細かいポイントの説明に入る前に、大雑把なレベルで理想的なサンプルコードについて確認しておきましょう。
以下は僕が考える理想的なサンプルコードです。
- 読み手(=見知らぬ第三者)のことを一番に考えて書かれている
- 読み手がすっと理解できるコードになっている
- 読み手(特に初心者)を正しい方向に導くコードになっている
上の条件をひっくり返すと、あまり望ましくないサンプルコードの定義が浮かび上がります。
- 自分のことしか考えていないコードになっている
- 読み手が首をかしげたり、理解するのに時間がかかったりするコードになっている
- 初心者がそのコードを何も考えずコピペすることで、バッドプラクティスを広めてしまう恐れがある
では、以下で「理想的なサンプルコード」を満たすための条件を具体的に見ていきます。
「当たり前品質」を満たしていること
サンプルコードは「当たり前品質」を当たり前に満たしておくべきです。
具体的には以下のような要件を満たしておく必要があります。
インデントが正しいこと
# ifに対応するendのインデントがおかしい
def some_method
  if foo?
    # ...
end
end
# OK(インデントが正しい)
def some_method
  if foo?
    # ...
  end
end
また、インデントさせるときはタブ文字よりも半角スペースを使う方が良いです。
適切な場所で改行したり半角スペースを挟んだりすること
# 半角スペースの使い方に一貫性がない
a= [1,2 ,3]
# OK(半角スペースの使い方に一貫性がある)
a = [1, 2, 3]
その言語の一般的な命名規則に従っていること
# Rubyのメソッド名をアッパーキャメルケースで定義することはめったにない
def SomeMethod
  # ...
end
# OK(Rubyのメソッド名はスネークケースで書くことが一般的)
def some_method
  # ...
end
文法的に正しいこと
コピペするだけ動くサンプルコードになっていることが理想です。
# ifに対応するendがない
def some_method
  if foo?
    # ...
end
# OK
def some_method
  if foo?
    # ...
  end
end
しれっと全角文字を混在させないこと
考え方としては先ほどの「文法的に正しいこと」の一種になります。
ときどき全角文字が紛れ込んでいるサンプルコードを見かけますが、こうしたコードは良くないです。
以下は文字列を囲むシングルクオートと、インデントのためのスペースが全角スペースになっている例です。
if name == ’Alice’
 # ...
end
当然コピペしても動かないですし、読み手も「言いたいことはわかるけど、なんか気持ち悪い」と強い違和感を抱くので、全角半角を正しく使い分けましょう。
# OK
if name == 'Alice'
  # ...
end
ここで挙げたような「当たり前品質」を満たしているかどうか自信がない初心者の人は、その言語に対応したLintツールを通すことを検討してみてください。
嘘をつかないこと
サンプルコードをコピペして実行したときに、説明している内容と同じ結果になっていることを確認しましょう。
そうならないサンプルコードは嘘をついているサンプルコードになります。
たとえば、下のコードは掛け算をしているのにaddというメソッド名になっています。
なので、add(2, 3)で5が返ってくることはありません。
def add(a, b)
  a * b
end
add(2, 3)
#=> 5
a * bではなく、a + bにすれば正しいコードになります。
def add(a, b)
  a + b
end
add(2, 3)
#=> 5
紛らわしい嘘コードを書かないこと
上に書いた「嘘をつかないこと」の一種ですが、このようなパターンもあります。
たとえば、以下のようなサンプルコードがあったとします。
def update
  if @ticket.update(ticket_update_params)
    redirect root_path, notice: '降車しました。'
  else
    render :edit
  end
end
おそらくRuby on Railsのサンプルコードだと思うのですが、よく見るとRailsプログラマが「そんなメソッドあったっけ?」と思うようなコードが紛れています。
# ん、redirectメソッドって何??
redirect root_path, notice: '降車しました。'
これは次のようにredirect_toと書くのが正解です。
# OK(redirect_toが正しい)
redirect_to root_path, notice: '降車しました。'
サンプルコードをいろいろ編集しているうちにうっかり間違えてしまったのだと思いますが、読み手は「あれあれ??」と混乱してしまうので、なるべくこういうミスは避けるようにしたいものです。
ブラウザのテキストエリア内でサンプルコードをいじくるとこういったミスが発生しやすいので、なるべく「実際に動くコード」を編集するようにして、最後に「ちゃんと動いたコード」をエディタやIDEからテキストエリアにコピペするのがお勧めです。
実行結果も一緒に載せること
コードだけ見せても、読み手は実行結果がぱっと予想できないことがあります。
(予想はついても確信が持てないこともあります)
ですので、実行結果も一緒に載せるようにしましょう。
たとえば、「10進数のRGBカラーコードを16進数の文字列に変換するメソッドを作りました」という説明とともに下のコードだけを見せられても、読み手は「🤔」となってしまいます。
def to_hex(r, g, b)
  [r, g, b].inject('#') do |hex, n|
    hex + n.to_s(16).rjust(2, '0')
  end
end
実行結果も一緒に示せば、「ほうほう、なるほど😄」と読み手もすぐに納得してくれます。
to_hex(0, 0, 0)       #=> #000000
to_hex(255, 255, 255) #=> #ffffff
to_hex(4, 60, 120)    #=> #043c78
コラム:参考にしたコードがあれば出典を明記すること
コードのわかりやすさと直結する話ではありませんが、書籍やネットからコードをコピペした(または一部改変した)場合は出典を明記しましょう。
# 以下のコードは「プロを目指す人のためのRuby入門」4.6.2項からの引用です
def to_hex(r, g, b)
  [r, g, b].inject('#') do |hex, n|
    hex + n.to_s(16).rjust(2, '0')
  end
end
参考:Qiitaで記事を公開するときに気を付けるべきマナーについて 〜無断でネットや書籍の内容を丸写しするのはやめよう〜 - Qiita
コードブロックやシンタックスハイライトを有効活用すること
Qiitaをはじめ、技術記事の執筆を支援しているブログサイトやWebサービスはコードブロックやシンタックスハイライトが使えるようになっています。
コードブロックやシンタックスハイライトを活用することで読みやすさが格段に変わってくるので、上手に活用しましょう。
以下はコードブロックもシンタックスハイライトも使わない例です。
(インデントは無視されます)
def to_hex(r, g, b)
 [r, g, b].inject('#') do |hex, n|
 hex + n.to_s(16).rjust(2, '0')
 end
end
以下はコードブロックを使った例です。(シンタックスハイライトは無し)
def to_hex(r, g, b)
  [r, g, b].inject('#') do |hex, n|
    hex + n.to_s(16).rjust(2, '0')
  end
end
以下はさらにRubyのシンタックスハイライトを加えた例です。
def to_hex(r, g, b)
  [r, g, b].inject('#') do |hex, n|
    hex + n.to_s(16).rjust(2, '0')
  end
end
コードブロックの左上にファイル名を表示させることもできます。
def to_hex(r, g, b)
  [r, g, b].inject('#') do |hex, n|
    hex + n.to_s(16).rjust(2, '0')
  end
end
Qiitaであれば、以下のページにMarkdown記法の使い方がまとまっているので、必ずチェックしておきましょう。
なお、技術記事の執筆を支援しているブログサイトやWebサービスではMarkdownを使って書けるようになっていることが多いですが、サイトごとに微妙に異なる「方言」を持っているので、各サイトのヘルプページを確認しておく方が良いです。
文章とコードの比率に気を付けること(理想は50:50)
記事内の文章とコードの比率も意識しましょう。
文章ばかりでコードがほとんどない技術記事は、読み手が頭の中でコードをイメージしなければならないので、読み手が苦労します。
また、具体的なコードを見せないと、筆者の意図が読み手に正しく伝わらない可能性もあります。
反対に、コードばかりで文章がほとんどない技術記事は、そのコードが何を意味しているのか、筆者がそのコードからどんなことを伝えようとしているのか、といったことを読み手が想像しなければなりません。
これもまた読み手に負担を強いることになります。
僕個人が考える、理想的な文章とコードの比率は50:50です。
つまり、文章とコードの分量が半々になっている技術記事が、読み手が最も理解しやすいのではないかと考えています。
コラム:仕事で書いたコードをコピペしないこと
仕事で書くコードは通常、社外秘になっているはずです。
ですので、仕事で書いたコードはそのままコピペせず、自分なりにアレンジしてうまくボカしましょう。
その際はできるだけこの記事に書いたチェックポイントに注意することをお勧めします。
続いて、ここから下のセクションでは「言うは易く行うは難し」で、場合によってはクリアするのが少し難しいかもしれないチェックポイントを書いていきます。
【やや難】意味のあるコードや実践的なコードを書くこと
foo、barやhoge、piyoといった用語しか並んでいないサンプルコードは、「そのコードでいったい何をしようとしているのか」「そのコードがどういうときに役立つのか」ということを理解しづらくなります。
以下はfoo、barみたいなクラス名や変数名しか出てこないサンプルコードの例です。
(ここではインスタンス変数の使い方を説明するコード例と仮定します)
class Foo
  attr_accessor :bar
  def initialize(bar)
    @bar = bar
  end
  def hoge(s)
    puts @bar + "\n" + s
  end
end
Foo.new('abc').hoge('xyz')
#=> abc
#   xyz
以下はfooやbarを使わずに、上のコードを多少意味のある形にしたサンプルコードの例です。
class Printer
  attr_accessor :header
  def initialize(header)
    @header = header
  end
  def print(s)
    puts @header + "\n" + s
  end
end
Printer.new('Page 1').print('Hello, world!')
#=> Page 1
#   Hello, world!
fooやbarしか使わないコードに比べれば、後者の方がまだコードの意図が理解しやすいのではないでしょうか。
理想としては、読み手が「なるほど、そりゃ便利だわ!」とか「あー、そういうこと、よくあるよね!」と思ってくれるようなサンプルコードを提供することです。
が、そういったサンプルコードを考えるのはなかなか骨が折れるのも確かです。
【やや難】できるだけシンプルなコードで説明すること
難しい内容を難しいまま提示しても、読み手はなかなか理解できません。
理想的なサンプルコードは、難しい内容を筆者が頭の中で上手に噛み砕き、説明したいトピックを最もシンプルな形で読み手に提示することです。
ですが、"Simple is not easy"とよく言われるように、シンプルさを追求することもまた、非常に骨が折れます。
簡単な内容から徐々に高度な内容へ発展させていくアプローチ
こういう場合は、すべての概念を1つのシンプルなコードで表現するのは至難の業なので、シンプルなコードを徐々に進化させていき、最終的に必要な知識を読み手に与える、というのがアプローチの1つです。
以下は以前執筆した「使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」」という記事からの抜粋です。
一番最初は以下のように最も単純なサンプルコードを使ってRSpecの構文を説明します。
RSpec.describe '四則演算' do
  it '1 + 1 は 2 になること' do
    expect(1 + 1).to eq 2
  end
end
これを徐々に進化させていき、以下のような構文を理解できるような説明の仕方をしました。
RSpec.describe '四則演算' do
  describe '足し算' do
    it '1 + 1 は 2 になること' do
      expect(1 + 1).to eq 2
    end
  end
  describe '引き算' do
    it '10 - 1 は 9 になること' do
      expect(10 - 1).to eq 9
    end
  end
end
より詳しく知りたい場合は元記事を参照してください。
使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita
【やや難】バッドプラクティスを書かないこと
自分の書いた技術記事はどこの誰が読むかわかりません。
熟練者から「ほとんど○○のことを知らない初心者さん」まで、いろんな人が自分の記事を読みに来ることが予想されます。
このとき、熟練者の人はまだ良いのですが、初心者さんは何も考えずに記事に載っているサンプルコードをコピペしてしまう可能性があります。
もし、サンプルコードがあまり好ましくないコードになっていると、そのコードがそのままあっちこっちに拡散してしまうことになります。
ここで1つ、具体例を出しましょう。
以下はRubyの例外処理を説明した"BADな"コード例です。
# Rubyの例外処理について説明している
# (が、コードとしてはあまりよくない)
begin
  some_method
rescue Exception => e
  puts "例外が発生しました: #{e}"
end
上のコード例ではExceptionクラスをrescueしています。
ですが、Rubyでは通常のプログラムで発生する可能性の高い例外はStandardErrorとそのサブクラスに束ねられているので、rescueするのはStandardErrorとそのサブクラスに限定すべきです。
Exceptionクラスを指定すると、通常回復不能な例外までrescueしてしまう恐れがあります。
さらに、StandardErrorとそのサブクラスをresuceしたい場合はrescue節に明示的に例外クラス名を書く必要がありません。
よって、例外処理を書くのであれば次のように書く方が適切です。
# OK(改善したくなる部分はまだあるが、さきほどのコードよりはマシ)
begin
  some_method
rescue => e
  puts "例外が発生しました: #{e}"
end
参考:Railsアプリケーションにおけるエラー処理(例外設計)の考え方 - Qiita
というわけで、上のサンプルコードに出てきたrescue Exceptionのように、バッドプラクティスと見なされるようなコードはサンプルコードとして書かないようにしましょう・・・と口で言うのは簡単なのですが、「バッドプラクティスを書いてやろう」と思って書く人は誰もいないですよね。
何がGOODで、何がBADなのかは、よっぽどの熟練者でないと自分で判断が付かないと思うので、このチェックポイントをクリアするのはなかなか難しいかもしれません。
【やや難】おかしな英語を使わない
これも非常に難しいですね。サンプルコードには変な英語を使うな、という話です。
難しい話ではあるのですが、最低限、配列は複数形で表す、ぐらいのルールは守ってほしいかなと思います。
# えっ、userって単数形なのに配列なの!?
user.each do |u|
  # ...
end
# OK(複数形になっていれば、自然と配列であることがイメージできる)
users.each do |u|
  # ...
end
それ以外は「なるべく気を付けましょう」としか言いようがありません。
僕自身も「お前は絶対100点満点の英語を使っているのか?」と聞かれたら、決してそんなことはないと思いますし。
でも、普段からおかしな英語を使わないように気を付けているのは確かです。
なお、ソースコードと正しい英語については以前こちらの記事にいろいろ書いたので、参考にしてみてください。
モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう - Qiita
まとめ
というわけで、この記事ではQiitaのような技術記事において、サンプルコードはどうあるべきか?という話題について論じてみました。
この記事に書いたチェックポイントをすべて満たそうとすると、1つの記事を執筆するのにかなり時間がかかると思います。
ですが、僕自身は技術記事や技術書を執筆する際にはいつもこうした点に注意しています。
全員が必ず従わなければいけないとは言いませんが、普段あまり深く考えずに技術記事を書いている人は、1つの考え方として参考にしてもらえると幸いです😃
あわせて読みたい
技術記事の執筆やサンプルコードのあり方について、僕がこれまでに書いた記事やスライドです。
よかったらこちらもどうぞ。