Help us understand the problem. What is going on with this article?

「よいサンプルコード」ってどんなサンプルコード? 〜Qiitaや技術ブログを書くときに気を付けること〜

はじめに

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

しれっと全角文字を混在させないこと

考え方としては先ほどの「文法的に正しいこと」の一種になります。
ときどき全角文字が紛れ込んでいるサンプルコードを見かけますが、こうしたコードは良くないです。

以下は文字列を囲むシングルクオートと、インデントのためのスペースが全角スペースになっている例です。(Qiitaで表示すると全角の部分が赤い下線で警告されます)

# シングルクオートとインデントのスペースが全角になっている
if name == Alice
 # ...
end

当然コピペしても動かないですし、読み手も「言いたいことはわかるけど、なんか気持ち悪い」と強い違和感を抱くので、全角半角を正しく使い分けましょう。

# OK
if name == 'Alice'
  # ...
end

ここで挙げたような「当たり前品質」を満たしているかどうか自信がない初心者の人は、その言語に対応したLintツールを通すことを検討してみてください。

嘘をつかないこと

サンプルコードをコピペして実行したときに、説明している内容と同じ結果になっていることを確認しましょう。
そうならないサンプルコードは嘘をついているサンプルコードになります。

たとえば、下のコードは掛け算をしているのにaddというメソッド名になっています。
なので、add(2, 3)で5が返ってくることはありません。

# addなのに掛け算?
def add(a, b)
  a * b
end

add(2, 3)
#=> 5

a * bではなく、a + bにすれば正しいコードになります。

# OK(+にすれば正しい)
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

もし画面上の見た目や動きが重要なサンプルコードであれば、以下のようにそのコードを実行したときのスクリーンショットを載せるのも有効です。

Screen Shot 2020-01-24 at 9.43.26.png

さらに、画面の動きをわかりやすく説明するために、アニメーションGIFを貼り付けておくのもひとつの手です。
僕はアニメーションGIFの作成にRecorditというツールを愛用しています。
以下はRecorditを使って作成したアニメーションGIFの例です。
OeXTaZPsSp.gif

コラム:参考にしたコードがあれば出典を明記すること

コードのわかりやすさと直結する話ではありませんが、書籍やネットからコードをコピペした(または一部改変した)場合は出典を明記しましょう。

# 以下のコードは「プロを目指す人のための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

コードブロックの左上にファイル名を表示させることもできます。

lib/rgb.rb
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記法の使い方がまとまっているので、必ずチェックしておきましょう。

Markdown記法 チートシート - Qiita

なお、技術記事の執筆を支援しているブログサイトやWebサービスではMarkdownを使って書けるようになっていることが多いですが、サイトごとに微妙に異なる「方言」を持っているので、各サイトのヘルプページを確認しておく方が良いです。

補足:コードやエラーメッセージをスクショ(画像)にしないこと

たまにサンプルコードをスクリーンショットにして載せる人がいますが、画像だと他の人がそのコードをコピーできないですし、スマホで見たときに極端に見にくくなったりすることがあります。
ですので、サンプルコードは必ずテキスト(とコードブロック)で書くようにしましょう。

↓ 画像にすると他の人がさっとコピーできないのでダメ!!🙅🏻‍♂️
Screen Shot 2020-01-13 at 7.51.54.png

スクショを使う理由として「強調のための下線や赤丸を入れたいから」という理由があるのかもしれませんが、そこはコメントをうまく活用してください。

def to_hex(r, g, b)
  [r, g, b].inject('#') do |hex, n|
    # 強調したいことがあれば、コメントで書こう!!
    hex + n.to_s(16).rjust(2, '0')
  end
end

これに似た話として、エラーの説明をするためにエラー画面をスクショで載せる人もよく見かけます。
ですが、これも他の人が情報をコピーしたり、画面上で内容を確認したりすることを難しくします。

↓ エラー画面も画像にするといろいろ不便!!🙅🏻‍♂️
Screen Shot 2020-01-13 at 8.08.04.png

ですので、エラーメッセージやスタックトレースもテキストとして載せるようにしてください。
(もしくはエラー画面のスクショと併用してください)

ちなみにRuby on Railsであれば通常、logs/development.logにエラー内容がログ出力されているはずなので、この内容をコピペして貼り付けるのがベストです。

logs/development.log
Started GET "/" for 127.0.0.1 at 2020-01-13 08:09:44 +0900
Processing by HomeController#index as HTML
Completed 500 Internal Server Error in 0ms

ZeroDivisionError (divided by 0):

app/controllers/home_controller.rb:6:in `/'
app/controllers/home_controller.rb:6:in `index'

また、エラーメッセージと一緒にエラーが発生したコードも載せておきましょう。
エラーに関する情報は、「エラーメッセージとスタックトレースと原因となったコード」の3点セットになっていないと役に立たないことが多いです。

class HomeController < ApplicationController

  skip_before_action :authenticate_user!

  def index
    a = 1 / 0
  end
end

文章とコードの比率に気を付けること(理想は50:50)

記事内の文章とコードの比率も意識しましょう。

文章ばかりでコードがほとんどない技術記事は、読み手が頭の中でコードをイメージしなければならないので、読み手が苦労します。
また、具体的なコードを見せないと、筆者の意図が読み手に正しく伝わらない可能性もあります。

反対に、コードばかりで文章がほとんどない技術記事は、そのコードが何を意味しているのか、筆者がそのコードからどんなことを伝えようとしているのか、といったことを読み手が想像しなければなりません。
これもまた読み手に負担を強いることになります。

僕個人が考える、理想的な文章とコードの比率は50:50です。
つまり、文章とコードの分量が半々になっている技術記事が、読み手が最も理解しやすいのではないかと考えています。

言語やライブラリのバージョンを明記すること

プログラミングの世界は移り変わりが激しいので、時間が経つと「以前は正しかったが、今はそうではない」ということがありえます。
もしくは実行環境に強く依存する技術情報だと「自分の環境では動くが、他の人の環境では動かない」ということも発生します。

ですので、技術記事には以下のような情報も載せておくことが望ましいです。

  • 言語のバージョン
  • フレームワークのバージョン
  • ライブラリのバージョン
  • OSのバージョン
  • RDBMSの種類(MySQL、PostgreSQL、Oracle等)とバージョン

特にSQLはRDBMSごとの方言や独自関数がたくさんあるので、どのRDBMSを使っているか明記しないと「記事の通りSQLを書いてみたが、エラーになった」という問題が発生しやすいです。

コラム:仕事で書いたコードをコピペしないこと

仕事で書くコードは通常、社外秘になっているはずです。
ですので、仕事で書いたコードはそのままコピペせず、自分なりにアレンジしてうまくボカしましょう。
その際はできるだけこの記事に書いたチェックポイントに注意しながら執筆することをお勧めします。
(ボカそうとした結果、誰の役にも立たないサンプルコードを書いてた、ということがないように)

続いて、ここから下のセクションでは「言うは易く行うは難し」で、場合によってはクリアするのが少し難しいかもしれないチェックポイントを書いていきます。

【やや難】コピペすれば動くコードになっていること

理想は「コピペすればすぐ動く」状態のサンプルコードになっていることです。
もし、別のライブラリをrequireしたりimportしたりする必要があるなら、それもコードに載せておきましょう。

# Ruby(Rails環境ではない素のRuby)はいきなりDateクラスを使おうとするとエラーになる
Date.today
#=> NameError (uninitialized constant Date)
# OK(dateライブラリをrequireすれば動く)
require 'date'
Date.today
#=> #<Date: 2020-01-13 ((2458862j,0s,0n),+0s,2299161j)>

ただし、大きなプログラムのごく一部を切り出した場合など、説明する内容によってはコピペするだけで動くサンプルコードにすることは難しい場合があります。
ですので、これは「可能ならそうする」という努力目標で構いません。

コード全体を載せられない場合は省略されていることがわかるようにすること

しかし、コード全体を載せられない場合でも省略したことがわかるようにしたり、省略した内容をコメントで補足したりすると、より読み手に優しいサンプルコードになります。

# ...を使って前後に省略した行があることをほのめかす
RSpec.configure do |config|
  # ...
  config.include FactoryBot::Syntax::Methods
  # ...
end
# ↓架空のメソッドをコメントで説明する例

# call_apiは外部APIを呼びだして結果をハッシュで返す架空のメソッド
result = call_api
case result
in {status: :success}
  "Success!"
in {status: :error, message: message}
  "Error: #{message}"
end

【やや難】意味のあるコードや実践的なコードを書くこと

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しか使わないコードに比べれば、後者の方がまだコードの意図が理解しやすいのではないでしょうか。

理想としては、読み手が「なるほど、そりゃ便利だわ!」とか「あー、そういうこと、よくあるよね!」と思ってくれるようなサンプルコードを提供することです。

が、そういったサンプルコードを考えるのはなかなか骨が折れるのも確かです。

ごく単純なサンプルコードであればfooやbarを使うのもアリ

fooやbarのような意味のないサンプルコードはなるべく避けるべきですが、ごく単純なサンプルコードであれば使っても問題ありません。

たとえば、以下は「Rubyのメソッド定義は値を返す」ということを説明するサンプルコードです。

name = def foo; end
name #=> :foo

上のコードにはfooが出てきますが、このサンプルコードは「メソッド定義が値を返す(その値は別に何でもよい)」ということを説明したいだけなので、fooを登場させても問題ありません。

この記事の冒頭でも書いたように「読み手がすっと理解できるコードになっていること」がサンプルコードの目的なので、fooを使っても理解のしやすさに悪影響がないと思ったときは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なのかは、よっぽどの熟練者でないと自分で判断が付かないと思うので、このチェックポイントをクリアするのはなかなか難しいかもしれません。
(RubyであればRuboCopBrakemanのようなツールである程度バッドプラクティスを検出できるかも?)

【やや難】説明の対象が何によって実現されているのか、ちゃんと理解すること

説明したい機能や仕組みが何によって実現されているのかをちゃんと理解できていないと、「合っているようで微妙に間違っている説明」をしてしまうことがあるので要注意です。

たとえば、Ruby on Railsであれば、RailsがRubyの標準ライブラリの機能を拡張しています。
具体例を挙げると、以下のblank?メソッドはRails(厳密にはActive Support)が独自に実装したメソッドです。

# blank?メソッドはRailsが独自に機能拡張して実装したメソッド
"".blank?    #=> true
"foo".blank? #=> false

もし、Rails以外の環境でblank?メソッドを実行しようとするとエラーが発生します。

# 素のRuby環境ではblank?メソッドは使えない
"foo".blank?
#=> NoMethodError (undefined method `blank?' for "foo":String)

ですので、上のようなサンプルコードを持ち出して「Rubyの便利メソッドを紹介します」と説明するのは、微妙におかしいです。
なぜなら、blank?メソッドはRubyが標準で提供している機能ではないからです。
この場合であれば、「Railsの便利メソッドを紹介します」と述べる方が適切です。

初心者の人は何が言語標準で、何がライブラリやフレームワークによって拡張された機能なのか、ぱっと識別できないかもしれません。
ですが、それでも「その機能が何によって実現されているのか」をできるかぎり意識して、「合っているようで微妙に間違っている説明」をしないように心がけてほしいと思います。

【やや難】おかしな英語を使わない

これも非常に難しいですね。サンプルコードには変な英語を使うな、という話です。
難しい話ではあるのですが、最低限、配列は複数形で表す、ぐらいのルールは守ってほしいかなと思います。

# えっ、userって単数形なのに配列なの!?
user.each do |u|
  # ...
end
# OK(複数形になっていれば、自然と配列であることがイメージできる)
users.each do |u|
  # ...
end

それ以外は「なるべく気を付けましょう」としか言いようがありません。
僕自身も「お前は絶対100点満点の英語を使っているのか?」と聞かれたら、決してそんなことはないと思いますし。
でも、普段からおかしな英語を使わないように気を付けているのは確かです。

なお、ソースコードと正しい英語については以前こちらの記事にいろいろ書いたので、参考にしてみてください。

モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう - Qiita

まとめ

というわけで、この記事ではQiitaのような技術記事において、サンプルコードはどうあるべきか?という話題について論じてみました。

この記事に書いたチェックポイントをすべて満たそうとすると、1つの記事を執筆するのにかなり時間がかかると思います。
ですが、僕自身は技術記事や技術書を執筆する際にはいつもこうした点に注意しています。

全員が必ず従わなければいけないとは言いませんが、普段あまり深く考えずに技術記事を書いている人は、1つの考え方として参考にしてもらえると幸いです😃

あわせて読みたい

技術記事の執筆やサンプルコードのあり方について、僕がこれまでに書いた記事やスライドです。
よかったらこちらもどうぞ。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away