サロゲートペアとRubyのStringについての覚書

はじめに

この記事は2020年ふりかえりアドベントカレンダー 10日目です。これを書いているのは12月14日ですが、あまり気にしないことにしました。昨日の記事は .irbrc で irb で使える独自メソッドを定義する - いまブログ です。

TL;DL

サロゲートペアは16ビット固定長で FFFF 外の文字を表現するために生まれた文字の表現方法です。

サロゲートペアが問題になるのは UTF-16 だけの話です。UTF-8 等では可変長のためこの表現方法を取っておらず、問題になりません。

おことわり

私は Unicode の歴史的経緯がよくわかっていないので正しい理解でないかもしれません。ですが、折角書いたり聞いたりしたのでまとめておきます。何か気になる点があれば、コメント、 twitter 等で連絡いただけるとありがたいです!

あらまし

フィヨルドブートキャンプの Slack で、 String55296 という数値を << で追加すると見慣れぬエラーになるという投稿がありました。

s = ""
s << 55296
# Main.rb:2:in `<main>': invalid codepoint 0xD800 in UTF-8 (RangeError)

その後別の方が調査して 0xD800サロゲートペアのコードポイントであると分かりました。

そこでサロゲートペアとはなんだろうということで調べてまとめて、以下の文をフィヨルドブートキャンプの Slack に投稿しました。(一部投稿時から編集しています)

サロゲートペアとは

サロゲートペアは Unicode が16ビットでは足りなくなったために生まれた、上位サロゲートと下位サロゲートを組み合わせて1つの文字を表現するための方法です。UTF-16 で使われています。他の Unicode エンコーディングでは使われていません。

もともと Unicode は16ビットの 固定長 として誕生しました。16ビットなので、16進数で 0000 〜 FFFF の65536文字を格納できます。

しかし、世界中の文字を格納するには65536文字では足りないことが分かりました。

そこで既存の固定長を前提にしているシステムを壊さないようにしつつ文字をもっと格納するためにサロゲートペアという仕組みがとられました。

サロゲートペアは上位サロゲートと下位サロゲートから構成されています。例えば「𠮷」(吉ではなく、土に口がついている字)を見てみます。 「𠮷」のコードポイントは U+20BB7 です。

> "𠮷".unpack("U*").each { p _1.to_s(16) }
"20bb7"

「𠮷」は、上位サロゲートが「D842」下位サロゲートが「DFB7」のコードポイントで出来ています。コードポイントから上位サロゲート・下位サロゲートを計算する方法は wikipedia とかに載っているので興味があれば...

余談ですが、実は RubyString"\unnnn"または "\u{nnnnn}" でコードポイントから文字に変換する機能があります。(nは16進数の数値。{}つけないほうは4桁までしか入りません)

試しに先程の 55296 を 16進数 D800 に直して表示しようとしてみると、同じ invalid Unicode codepoint というエラーになります。

irb(main):030:0> 55296.to_s(16)
=> "d800"
irb(main):032:0> "\ud800"
Traceback (most recent call last):
        3: from /Users/mi/.rbenv/versions/2.7.1/bin/irb:23:in `<main>'
        2: from /Users/mi/.rbenv/versions/2.7.1/bin/irb:23:in `load'
        1: from /Users/mi/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/irb-1.2.7/exe/irb:11:in `<top (required)>'
SyntaxError ((irb):32: invalid Unicode codepoint)
"\ud800"
   ^~~~

もっと Ruby の String とエンコーディングの話

フィヨルドブートキャンプに投稿したバージョンでは、以下の文を入れていました。その後教えていただいて誤りがあると分かったので教えていただいた内容を簡単にまとめます。

上位サロゲート、下位サロゲートは1文字では文字として成り立たないため、s << 55296 のようにStringに挿入しようとすると「変なもの入れてますよ!!」とエラーがでるのだと思います。

"\uD800" とは何をしているのか

これは String オブジェクトを __ENCODING__ に指定されたエンコーディングで作成する処理です。

疑似変数 __ENCODING__スクリプトエンコーディングを持っており、最近の環境では UTF-8 が多いかと思います。

"あ" のように ' " で文字列をくくると RubyString オブジェクトを生成します。このとき、 疑似変数 __ENCODING__エンコードされた String オブジェクト を生成します。

エンコードするときに壊れた文字データが入っていた場合は例外を出します。このため、上位サロゲート文字の "\uD800" は1文字では文字として成り立たないためエラーになっていました。

やり方を変えて、String.new するときに encoding 情報を渡すとエンコードされないため例外になりません。RubyString に壊れた文字をもたせること自体は問題なく、 ""String オブジェクトを作成したときにエンコードが走り正しい値かチェックされていたことが原因で例外を吐いていたということが分かりました。

String.new("\xD8\x00", encoding: Encoding::UTF_8)
=> "\xD8\u0000"

.irbrc で irb で使える独自メソッドを定義する

はじめに

この記事は2020年ふりかえりアドベントカレンダー 9日目です。これを書いているのは12月12日ですが、あまり気にしないことにします。昨日の記事は Hamada.rb #16 に参加 - いまブログ です。

今日は以下のツイートで教えていただいた内容についてまとめます。

.irbrc とは

irb の設定ファイルです。ホームディレクトリに置くと、どこから irb を起動しても読み込まれます。ホームディレクトリに .irbrc がない場合、カレントディレクトリの .irbrc , irb.rc , _irbrc , $irbrc を順番にロードしようと試みます。

ちなみに Ruby 2.7 からの irb は、複数行編集、シンタックスハイライト、入力履歴など便利な機能がたくさん追加されてとても使いやすく便利になりました。 irb を使うなら Ruby 2.7 以上の環境で使うことをおすすめします。

.irbrcRuby スクリプトなので中に Ruby のコードを書くことができます。

また、 irb の設定値も定義できます。詳細はこちらを参照してください。

library irb (Ruby 2.7.0 リファレンスマニュアル)

class IRB::Context (Ruby 2.7.0 リファレンスマニュアル)

irb に独自メソッドを定義したくなった

さて irb を使うときに特定のメソッドを頻繁に呼び出しすることがあります。

例えば、私は文字コードを確認することが多いためこのようなメソッドを頻繁に使います。

"🐈".ord.to_s(16)
=> "1f408"

このように each_codepoint にブロックを渡す処理もよく書きます。

 "☃️".each_codepoint { p _1.to_s(16) }
"2603"
"fe0f"
=> "☃️"

ord each_codepoint の詳細についてはこちらの記事に書きましたので、もし興味があればご覧ください。

Rubyで文字コードを扱うコードを書くときに便利なメソッド集 - Qiita

これらは決まりきった書き方で、一々入力するのがとても面倒でした。 Dash というアプリでスニペットを登録するか悩んでいたところ、twitter で .irbrc でクラス拡張すればいいんじゃない? と教えてもらったのでそうすることにしました。

.irbrc でクラス拡張(オープンクラス)する

Ruby では組み込みライブラリも自由に書き換えることができます。

今回は String クラスに便利メソッドを定義しました。

~/.irbrc

class String
  def each_codepoint16
    each_codepoint { |s| p s.to_s(16) }
  end

  def ord16
    ord.to_s(16)
  end
end

irb を起動すると、特に何も読み込みしなくても定義したメソッドを呼び出せます。便利!

❯ irb
irb(main):001:0> "🐈".ord16
=> "1f408"
irb(main):003:0>  "☃️".each_codepoint16
"2603"
"fe0f"
=> "☃️"

クラス拡張ですので、既存のメソッドの上書きや、バージョンアップで同名のメソッドが追加されると挙動がおかしくなる可能性があります。

独自メソッドを定義する際は、 Ruby に追加されなさそうなメソッド名にしておくと良いと思います。

参考資料

Hamada.rb #16 に参加

この記事は2020年ふりかえりアドベントカレンダー 8日目です。昨日の記事は yarn install 時の gyp: No Xcode or CLT version detected! を解消する - いまブログ です。

島根県浜田市Ruby コミュニティ、 Hamada.rb に参加しました。現在はオンラインで開催されています。

hamadarb.connpass.com

同時に Ruby Hacking Challenge in Hamada.rb も開催されています。

hamadarb.connpass.com

Ruby 3.0 preview-2

今日はちょうど Ruby 3.0 preview-2 がリリースされたので、リリースノートをみんなで読んでいました。

www.ruby-lang.org

リリースノートのリンク切れを見つけ、勉強会中に PR を立てている方がいました。

www.ruby-lang.org 用のリポジトリがあると知らなかったので勉強になりました。

github.com

github.com

bundled gems ?

リリースノートにこんな一文がありました。

以下のライブラリが新たに bundled gems になりました。Bundler から利用する場合は Gemfile に明示的に指定してください。(中略) 以下のライブラリが新たに default gems になりました。rubygems.org からアップデート可能です。

bundled gems と default gems とはなんでしょうか?

調べてみたところこういった違いがあるようです。

ライブラリ 扱い
標準ライブラリ Builtin libraries, 組み込みライブラリとも呼ぶ。 require 不要で使える Array, String など
標準添付ライブラリ Ruby に同梱されているライブラリ。 require すれば使える。 bundled gems と default gems に分かれる。 -
bundled gems Ruby に同梱されているが、gem uninstall ができる gem 。Bundler から使う場合は Gemfile に指定する minitest など
default gems Ruby に同梱されており、gem uninstall できない gem 。 rubygems.org からアップデート可能 irb, reline など

間違っていたらご指摘ください🙏

試しに reline をアンインストールしてみようとしたら怒られました。

$ gem uninstall reline           
Gem reline-0.1.5 cannot be uninstalled because it is a default gem

ちなみに bundled gems と default gems はこちらで定義されています。

ruby/bundled_gems at ruby_2_7 · ruby/ruby

ruby/sync_default_gems.rb at master · ruby/ruby

参考資料

bundled gem と default gem の違い - @znz blog

bundled gem と default gem の違いの具体例 - @znz blog

irb のバグ

以前から気になっていた irb のバグっぽい挙動を相談しました。

他の方も同じ挙動が確認できたこと、自力で直すのが大変そうなこと(Ruby で書かれている irb ならともかく、 CRuby 本体の Warning 周りに原因があると私にはお手上げです)、Ruby 3.0 リリースまでに直っていてほしいと思ったことからチケットを起票しました。

Hamada.rb は CRuby の貢献フローになれている方が多く、いろいろアドバイスいただいてすぐに起票できました。

詳細はこちらをご覧ください。

bugs.ruby-lang.org

英語書くのにとても悩んで時間がかかりました。チケットを書く時間の90%は英語で悩んでいた時間と言っても過言ではありません。リーディング・ライティング力を身に着けたいです。

今日はこんなところで。

yarn install 時の gyp: No Xcode or CLT version detected! を解消する

この記事は2020年ふりかえりアドベントカレンダー 7日目です。昨日の記事は GitHub CLIでgistを作成する - いまブログ です。

rails new とか rails s 時に yarn install --check-files を促され、 gyp: No Xcode or CLT version detected! で落ちたときの対処法です。

例えばこんなエラーメッセージ

$ rails new taskleaf -d postgresql
中略
gyp info spawn args ]
No receipt for 'com.apple.pkg.CLTools_Executables' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLILeo' found at '/'.

No receipt for 'com.apple.pkg.DeveloperToolsCLI' found at '/'.

gyp: No Xcode or CLT version detected!
gyp ERR! configure error 
gyp ERR! stack Error: `gyp` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onCpExit (/Users/ku-jaku/.nodebrew/node/v12.8.0/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:344:16)
gyp ERR! stack     at ChildProcess.emit (events.js:203:13)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:272:12)
gyp ERR! System Darwin 19.3.0
gyp ERR! command \"/Users/ku-jaku/.nodebrew/node/v12.8.0/bin/node\" \"/Users/ku-jaku/.nodebrew/node/v12.8.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js\" \"rebuild\"
gyp ERR! cwd /Users/ku-jaku/ku-jaku/2019fjordbootcamp/taskleaf/node_modules/fsevents
gyp ERR! node -v v12.8.0
gyp ERR! node-gyp -v v5.0.3

途中に出ているのでわかりにくいのですが、 gyp: No Xcode or CLT version detected! と出力されています。

解消法

Xcode を再インストールします

$ pkgutil --packages | grep CL
# 何も表示されないことを確認
$ sudo rm -rf $(xcode-select -print-path)
$ xcode-select --install

参考資料

GitHub CLIでgistを作成する

はじめに

この記事は2020年ふりかえりアドベントカレンダー 6日目です。昨日の記事は Rubyにはオブジェクトを汚染する仕組みがあった - いまブログ です。

GitHub CLIとは

GitHub 公式が提供している CLI ツールです。コマンドラインから Pull Request や issue を管理したり、 gist を作成できて便利です。

cli/cli: GitHub’s official command line tool

GitHub CLI では gist の作成、確認、編集、削除ができます。つまり好きなエディタで gist に上げたファイルを操作できます!

とてもシンプルに gist 管理ができて便利だったので使い方を紹介します。

GitHub CLI のインストール

macOS の場合は homebrew でインストールできます。

$ brew install gh

LinuxWindows などの環境のインストール方法は README に書いてあります。 cli/cli: GitHub’s official command line tool

GitHub CLI のコマンドは gh で呼び出せます。

インストール後、 適当な gh コマンドを打って GitHub アカウントにログインしてください。

$ gh issue list 

gist を作成

コマンド

$ gh gist create [<filename>... | -] [flags]

-p オプションを指定しない場合 secret gist が作成されます。

オプション

-d, --desc      # gist の詳細を記入
-p, --public   # gist を public で作成
-w, --web       # 作成した gist をブラウザで表示

サンプルコード

$ gh gist create test.txt -w
- Creating gist test.txt
✓ Created gist test.txt
Opening gist.github.com/afe55d913bad0dc92f1c41c0f7392f97 in your browser.

$ gh gist create test.txt -d "説明" -p -w
- Creating gist test.txt
✓ Created gist test.txt
Opening gist.github.com/061e2ce872d3e331d1e2f054bd478363 in your browser.

gist の一覧を確認

gist id、説明文、ファイル数、公開状態、最終更新時間を確認できます。

コマンド

$ gh gist list [flags]

サンプルコード

$ gh gist list                           
061e2ce872d3e331d1e2f054bd478363  説明            1 file  public  less than a minute ago
afe55d913bad0dc92f1c41c0f7392f97  test.txt        1 file  secret  about 3 minutes ago

gist を確認

cat コマンドのように gist を表示できます。

コマンド

$ gh gist view {<gist id> | <gist url>} [flags]

サンプルコード

$ gh gist view 061e2ce872d3e331d1e2f054bd478363 
説明
GitHub CLI でアップロードしたサンプルファイルです。

markdown の場合少し色がついた状態で表示されます。

gist を編集

エディタで gist を開いて編集できます。

コマンド

$ gh gist edit {<gist ID> | <gist URL>} [flags]

エディタが開いて gist を編集できます。使うエディタは環境変数 EDITOR を参照しています。

サンプルコード

$ gh gist edit 67353016314581ed675e40e7f89ea422 

$ EDITOR="nano" gh gist edit 67353016314581ed675e40e7f89ea422 

私の環境では、EDITOR="code" (VSCode) を指定するとうまく編集できませんでした。

gist を削除

gist を削除します。特に確認メッセージなどは出てこないので注意してください。

コマンド

$ gh gist delete {<gist ID> | <gist URL>} [flags]

サンプルコード

$ gh gist delete 67353016314581ed675e40e7f89ea422    

参考資料

Rubyにはオブジェクトを汚染する仕組みがあった

はじめに

Ruby 3.0 Advent Calendar 2020 5日目の記事です。

昨日は、【Ruby 3.0 Advent Calendar 2020】Ruby3.0で非推奨から廃止になるメソッドたち【4日目】 - ゲームリンクスの徒然なる日常 です。

また、この記事は2020年ふりかえりアドベントカレンダー 5日目です。昨日の記事は 初学者が Ruby on Rails の広大さに途方にくれたけどなんとかやっていけるようになった話 - いまブログ です。

Ruby 3.0 から $SAFE が普通のグローバル変数になります

The feature of $SAFE was completely removed; now it is a normal global variable.

The feature of $SAFE was completely removed; now it is a normal global variable. ruby/NEWS.md at v3_0_0_preview1 · ruby/ruby

ということで、 $SAFE という特殊変数が普通のグローバル変数になります。ところで $SAFE とはなんでしょうか?これは Ruby のオブジェクトを汚染するセキュリティの仕組みに関わっていた特殊変数でした。

Ruby のオブジェクト汚染の仕組みについてざっくり説明し、$SAFE がなんだったのか、なぜ取り除かれるのか、というところをまとめてみます。

オブジェクトを汚染する仕組み

Ruby にはオブジェクト汚染という仕組みがありました。これは、オブジェクトの汚染とセーフレベルという仕組みで「外部から与えられた信頼できないオブジェクトを安全に取り扱う」こと、「信用しているオブジェクトを信用できないプログラムから守る」ことを目的としていました。CGI 時代に入力フォームから受け取ったデータを信頼しないようにしたい、という使われ方をしていたようです。

ちなみに、汚染という考え方は Perl 由来の機能です。Taint checking - Wikipedia

オブジェクトを汚染する

オブジェクト自体に汚染フラグを持つ仕組みです。汚染に関連するメソッドはこのようなものがありました。

  • Object#taint オブジェクトを汚染する
  • Object#tainted? オブジェクトが汚染されている場合に真を返す
  • Object#untaint オブジェクトの汚染を取り除く

これらのメソッドは Ruby 2.7 より非推奨となりました。 taint untaintself を返す挙動に、 tainted? は常に false を返すようになっています。 似たような trust untrusted? untrust メソッドもありますが、こちらも非推奨です。

これらのメソッドは Ruby 3.2 で削除される予定です。

セーフモデル

信用できないデータで危険な操作( eval やファイル操作、外部コマンド実行など) を行えないようにするための仕組みです。セーフレベルはレベル0〜レベル4まであり、レベル4ではプログラムを自由に終了することもできませんでした。セーフレベルはグローバル変数 $SAFE で設定することができました。

なぜこの仕組みは消えることになったか

汚染という仕組みには、

  • Ruby と関係するすべての C コードの汚染レベルとセーフレベルをチェックする必要があり、メンテナンスコストも嵩む、パフォーマンスも悪くなる
  • セキュリティを担保するレベルが粗い。汚染の仕組みを使ってセキュアなプログラムにしようと思うと多くのプログラムが動かない
  • 汚染を適切に運用していないオブジェクトがあるとセキュリティを担保できない

といった問題がありました。

また、 セーフレベル4は安全な sandbox 環境のために使えると思われていましたが、実際には脆弱性がありました。

汚染の仕組みは CGI で活用されていましたが、Ruby on Rails の台頭により CGI の必要性が下がったという理由もあったようです。

今までの流れとこれから

Ruby 2.1 でセーフレベル4が廃止されました。ruby/NEWS at v2_1_0 · ruby/ruby

Ruby 2.3 でセーフレベル2, 3が廃止されました。ruby/NEWS at ruby_2_3 · ruby/ruby

残ったセーフレベルは0(すべて信頼する)1(汚染されたオブジェクトは evalやファイル操作、外部コマンドの実行を禁止する)でした。

Ruby 2.7 を前に、汚染の仕組みを完全に廃止してはどうかというチケットが立てられました。Feature #16131: Remove $SAFE, taint and trust - Ruby master - Ruby Issue Tracking System

廃止の理由は

  • この仕組みを使っている人がほとんどおらず、ライブラリもサポートしていないこと
  • 脆弱性があり、メンテナンスコストがかかっていること

です。

このチケットで議論が行われ、

  • Ruby 2.7で 汚染の仕組みを使えないようにする。 $SAFEtaint 系のメソッドで警告を出す
  • Ruby 3.0 で $SAFE をふつうの変数にする
  • Ruby 3.2 で taint 系のメソッドを削除する

ということが決まり、削除されることになりました。

参考資料

初学者が Ruby on Rails の広大さに途方にくれたけどなんとかやっていけるようになった話

これは「フィヨルドブートキャンプ Part 1 Advent Calendar 2020」の4日目の記事です。

フィヨルドブートキャンプ Part 1 Advent Calendar 2020 - Adventar

昨日は hogucc さんの Rubyでリファクタリングをやってみよう でした。

Part2 もあります。

フィヨルドブートキャンプ Part 2 Advent Calendar 2020 - Adventar

また、この記事は2020年ふりかえりアドベントカレンダー 4日目です。昨日の記事は 「数学ガールの秘密ノート/学ぶための対話」感想 です。

今日はフィヨルドブートキャンプで最も苦しんだプラクティス、Ruby on Rails についての思い出を書こうと思います。随分長くなってしまいましたが、ふわっとした話なので暇なときにでもどうぞ..

フィヨルドブートキャンプで Ruby on Rails を学ぶまで

フィヨルドブートキャンプでは全体の中盤くらいに Ruby on Rails のカリキュラムがあります。

学習内容 | FJORD BOOT CAMP(フィヨルドブートキャンプ) でプラクティスのタイトルは公開されており、赤く囲った枠が Rails です。プラクティスは基本的に順番通り進めることが推奨されているため、Rails は全体の中盤くらいから学びはじめることになっています。ちなみにプラクティスの内容・順番は随時更新されているので最新版はリンク先を参照してください。

f:id:imaizumimr:20201204223758p:plain

私はフィヨルドブートキャンプで学習をはじめてから4ヶ月程度で Rails のカリキュラムに到達しました。

Rails エンジニアになるぞ!!と思ってフィヨルドブートキャンプに参加したので、やっと Rails だー嬉しいー!と思った記憶があります。また、フィヨルドブートキャンプの現在のプラクティスでは Sinatra で web アプリをつくってから Rails に入る流れなので、Rails で web アプリ作るの Sinatra よりめちゃくちゃ楽じゃん...と感動しました。

しかし、そこからが大変だったのです…

rails new したらたくさんディレクトリが出来るけど、なにもわからない

私が Rails を学んだ初日の日報にこんなことを書いていました。

Railsディレクトリ構成がよくわからない。やっていたらいずれ分かるものだろうか?

これは、例えば app/models とか app/controllers がよくわからない、どこに何があるかも分からないし、何かを参考にしようにもフルパスで書いてないとどこに何を書いていいか分からないという状態でした。

分からないので調べよう、と思って調べてみても、その時点の知識レベルでは Rails ガイドに何が書いてあるのかもさっぱり分からない状態です。

日報で「わからないまま進めることに不安がある」と書くとフィヨルドブートキャンプの先輩の id:NMP300 さんから、

結局は自分で手を動かして、悩んだり苦しんだりしないと、本やサイトを読んだだけでは、あまり理解できないのかな、と思いました🤔

とアドバイスをいただいたので、とりあえず手を動かして悩んだり苦しんだりすることにしました。

Rails なにもわからない

過去の日報に悩んだり苦しんでいる様子がいろいろあったので抜粋して紹介します。Rails の学習をはじめて2〜3ヶ月間のコメントです。

  • Rails はどこに何が定義されているのかわからない
  • i18nt メソッドって何?と思ってもどこにコードがあるのかわからない
  • Rails で意味があるファイルなのかただのサンプルファイルなのかぱっと見で見分けられなくて難しい
  • devise の課題で、これどうやって理解しよう…と思って悩んでしまって手をつけられない時間が長くなってしまった
  • devise のルーティングがわからない
  • devise が分からないまま動いていることにモチベが下がる
  • devise がなんか resource ってオブジェクト使ってるけどこれはなんなんだろう
  • テスト周りで、自分が使いたい機能が何のgemの機能なのか把握するのが大変
  • i18n で翻訳するにはt ".email"のようにI18n.tメソッドを使うものだと思っているのだけど、シンボルだけで翻訳できているパターンがあって理由がわからない
  • Rails 何も理解できてないんじゃ…という不安感が常にある。どうしたものかな🧐
  • Rails 理解してスッキリ Rails のコードを書きたい!
  • Railsに対する苦手意識が生まれてしまっている気がするので、苦手意識をなくしたい🤔🤔

かなり悩んでそうな感じになっています。実際、一時期は自分は Rails わからなさすぎて Rails エンジニアに向いてないんじゃないかと考えていました。

日報に書いたところはメンターさんから都度アドバイスや回答はいただいていましたが、自分としては根本的に Rails への理解が足りないなあという不安がしんしんと積もっていきました。

一つ何かを理解すると、その周囲にあるわからないことがどんどん見えてくるんですよね。例えると、真っ暗なところをろうそくの灯火でうっすらと道を見て歩いている…と思っていたのに、懐中電灯をゲットしたので使ってみたら、道じゃなくて原っぱを歩いているしまわりには得体のしれないものがいっぱいあって、ろうそくを使っていたときより明るくなっているのに逆に不安になるような、そんな気持ちでした。少しずつ分かっていることは増えているはずなのに、わからないことのほうが増えていく状態がとても不安でした。自分が立っている場所もよく見えないようなそんな感じでした。

Rails の gem のコードを読める環境をつくって読んでいったり、Railsガイドを読んだり、手を動かしてプラクティスを進めたりしていましたが Rails への苦手意識はつのるばかりでした。

そうこうしているうちに Rails を学習しはじめてから数ヶ月がたち、スッキリコード書けないまま進めたツケなのか完全に Rails が嫌になってしまいました。AtCoder やってみたり、英語学習してみたりと Rails からの逃避をはじめました。

ラクティス的には進めようと思えば進められる状況でした。やろうと思えば..コードの意味を追わなければ..コードは書ける、でも、そうやって書きたくない…という気持ちでもやもやしていました。日報を書く回数も減っていって、周りからは少し心配されていたような気がします。

Entaku.rb

Rails の進捗は悪くなっていっていましたが、そのころから Ruby コミュニティに参加しはじめていました。フィヨルドブートキャンプの先輩の id:s4na さんから、「Rails のプラクティスを始めたら地域 Ruby コミュニティに参加するといいですよ!」と勧められていたので、私も Rails を学び始めたから参加してみるかぁという軽い気持ちでした。2020年4月〜5月頃です。当時新型コロナウイルスが流行しており、勉強会は休止かオンラインになっていました。

そんな中で、twitter で Entaku.rb という勉強会の存在を知りました。

Entaku.rbは日本語での技術ディスカッションをメインとしたコミュニティです。名前に".rb"とあるようにRuby周辺の話題を主に取り扱いますが、参加者の方が話題を決めるため、何を議論するかは都度変わります。 議論は4人ほどの少人数グループによって行われます。各グループによって何を議論するかは異なり、最後に全グループで何を話し合ったかや何を得られたかを共有します。

Entaku.rb | Doorkeeper

Entaku-rb/minutes: 議事録

ここで Rails の学習に関する悩みについて質問したことがきっかけで、Rails スランプを抜け出せました。

Rails は gem の集まり

当時の自分のモヤモヤを要約すると「Rails について「こうしたらこうなる」は分かるが、なぜそうなるかが分からず壁を感じている」でした。

その問題に対し、参加者でワイワイ議論したのですが私としては「Rails は個々の gem が集まって出来ている。細かいコードを追うのではなく、大きな gem 同士の関係性を知ったほうが理解するのに役に立つかも」という回答がとても参考になりました。

これまでは Rails を使っていてわからないことがあるとまずコードレベル、メソッドレベルで追いかけて「ようわからんなあ」と思っていました。

しかし各々の gem がどういう役割なのかを知ることが大事だと分かりました。また、プロのエンジニアでもコードレベルで細かい処理の流れを追うことはほとんどないということを知れたのも良かったです。それまで自分は Rails をコードの集合体としか見れていませんでした。プログラムはコードから成り立っているものだからコードを見れば分かるはずだと思っていました。でも、もっとレイヤの高い視点で見ることができて、Rails は gem が協調して動いているということが Entaku.rb のおかげで分かったんですよね。それは、自分にとっては目から鱗が落ちるかのような発見でした。

それまでコードの狭い世界で見ていたものが、もう一段広い gem 同士のつながりという世界で見られるようになりました。文字通り世界が広がったような気持ちでした。木を見て森を見ずという言葉がありますが、まさに自分がその状態でした。森という概念を知らないまま、全体像が分からないよ・・・と木ばかり見ていた感じです。

それ以外にも、「Railsの思想はSimpleでなくてEasyで「とにかくこのように書け」というものなので、ある程度の諦めは肝心かもしれない」とか、全てを「理解している」まで持っていかなくてもよくて「知っている」でも良いとか、非常に学びの多い勉強会でした。

当時の議事録です:minutes/Railsの勉強法.md at master · Entaku-rb/minutes

そして現場 Rails

Rails の見え方が変わって気持ちを新たにした私は、とりあえず『現場Rails』を読んで基礎を学ぶことにしました。

現場RailsRails の学習開始1ヶ月くらいで少し読んでいたんですが、そのときは書いてある内容が全然ピンときませんでした。

それが、4ヶ月くらい悩んだり苦しんだりした後に読むと全然見え方が変わっていて、知りたかったことがたくさん書いてあって読んでてめちゃくちゃ楽しい本に見えるようになっていました。

現場Rails を読み終わるころには Rails への苦手意識もなくなり、プラクティスを進められるようになりました。

結局は自分で手を動かして、悩んだり苦しんだりしないと、本やサイトを読んだだけでは、あまり理解できないのかな、と思いました🤔

これは最初にいただいたアドバイスですが、本当にこのとおりでした。

悩んだり苦しんだりして、ようやく分かること、気づくこともあります。Rails のプラクティスではスランプになったり、Rails エンジニアやっていけるのか悩んだり、いろいろありましたがそのおかげで理解できるようになったことがたくさんありました。悩みを質問する過程でたくさんのことを学びました。自分では気づけなかった視点を持つこともできました。

Rails はまだまだ分からないことだらけですが、今の自分はあのときの自分よりたくさんの武器を持っています。いろいろな角度で問題を眺めることができるようになりました。これまでの学びを血肉としてなんとかやっていっています。でもまだまだこれからが本番です。今後もなんとかやっていきたいなあと思います。

謝辞

Entaku.rb でアドバイスいただいた id:okuramasafumi , id:osyo-manga ,参加していた皆様にとても感謝しています。あの Entaku.rb から Ruby コミュニティにハマって今に至るので、あの会がなければ今の自分はありませんでした。ありがとうございます。