Roll With IT

tamakiのIT日記

チェリー本輪読会 第16週目まとめ

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本輪読会の第16週目のエントリーになります。

輪読会の概要については第1週目にまとめています。

🍒 輪読会 第16週目まとめ

第11章11.1.1〜第11章11.6まで

期間:2021年9月6日〜2021年9月10日

デバッグ とは

第11章はRubyデバッグ技法について章になります。

デバッグとは、プログラムで起こる不具合の原因を探し出し直すことを指します。

デバッグ - Wikipedia

バックトレース とは

プログラムの実行中にエラー(例外)が発生すると、出力される情報のことをバックトレースと呼びます。以下、リンク先の資料には、「メソッドの呼び出し状況を表したデータ」と書いてありました。

Ruby でのバックトレース活用法

バックトレースは、上に行くほどエラーに近いので、一番上がエラーの発生場所になります。

エラー内容が上から下に遡る(trace back to)しています。

よく発生する例外クラス(Exceptionクラス)

アプリケーションの実行中に発生するエラーを表すオブジェクトです。

るりまには多く例外クラスが掲載されています。

docs.ruby-lang.org

その中でも発生頻度の多い例外クラスがチェリー本では解説されています。

  • NameError
    • 未定義のローカル変数や定数、privateメソッドなどを呼び出したときに発生
  • NoMethodError
    • 存在しないメソッドを呼び出そうとしたときに発生
  • TypeError
    • 期待しないクラスがメソッドの引数に渡されたときに発生
  • ArgumentError
    • 引数の数が違ったり、期待する値ではなかったりした場合に発生
  • ZeroDivisionError
    • 整数を0で除算しようとしたときに発生(1/0 のように0で割ってはいけないとき)
  • SystemStackError
  • LoadError
    • requireやloadに失敗したときに発生
  • SystemError(syntax error)
    • 構文エラー、endやカンマの不足、丸括弧などが閉じていないなどが原因で発

printデバッグ

printデバッグは、簡単ですぐに使えるデバック方法です。私も一番最初に覚えました。

printデバッグと呼びますが、主に、pputs を使って行われます。変数やメソッドの値を出力したり、条件分岐が意図した通りに実行されているかどうかを確認したりに使えます。

printデバックと呼ばれる方法は以下の4つのメソッドが存在します。

  • printメソッド
  • putsメソッド
  • pメソッド
  • ppメソッド(prity printの略)

デバッカ(Byebug)を使う

デバッガを使えば対話的にデバッグをすることができます。

プログラムをステップ実行しながら変数の中身を確認したり、実行される条件分岐を確認したりすることができます。

Rubyの標準ライブラリとして提供されているdebugライブラリがありますが、開発の現場ではdebugライブラリよりも、Byebugという外部ライブラリ(Gem)が使われることが多いようです。

使い方については、伊藤さんのByebugチュートリアルが参考になります。

qiita.com

binding.irb

チェリー本では紹介されていませんが、フィヨルドブートキャンプのメンターさんからbinding.irbを使ったデバッグ方法も伝授していただきましたので紹介したいと思います。

下記のコードようにbinding.irbを挟むと、そこでデバック作業が発動し、irbが起動するしくみです。

def fizz_buzz(n)
  if n % 15 == 0
    "Fizz Buzz"
  elsif n % 3  == 0
    "Fizz"
  elsif n % 5 == 0
    "Buzz"
  else
    n.to_s
  end
end
binding.irb

ブレークポイントirbが起動するので、試したいコードを打ち込むことが可能になります。

今回は、fizz_buzzメソッドを入力してみました。

$ ruby test/fizz_buzz_test.rb
lib/fizzbuzz.rb @ line 12 :

     7:     "Buzz"
     8:   else
     9:     n.to_s
    10:   end
    11: end
 => 12: binding.irb
    13:
    14:
    15: # require 'minitest/autorun'
    16: #
    17: # class FizzBuzzTest < Minitest::Test

irb(main):001:0> fizz_buzz(15)
=> "Fizz Buzz"
irb(main):002:0> fizz_buzz(99)
=> "Fizz"
irb(main):003:0> fizz_buzz(7)
=> "7"

binding.irb を使ったやり方のメリットはデバッガ等の設定をしなくて済むので手軽であること、コードを止めた時点でアクセス(利用)可能な変数やメソッドにアクセスできるので好き勝手コードを打って試行錯誤が試せることです。

「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意

以下では、デバッグの基本と極意が学べます。

qiita.com

日々ハマりまくっているので偉そうなことは書けませんが、デバッグって本当に初心者の方の壁だと思っています。同じバグで何日も詰まったことは数知れず。心が何度も折れそうになりました。。。 何度もメンターさんにペアプロしていただいて助けていただいています。そんな時に痛感することなのですが、メンターさんのデバッグの的確さ、そして速さ。本当に魔法のように問題が解決していきます。

まだまだ初心者を抜け出せたとは言えないませんが、この動画や本書の内容を日々実践し、デバッグ力を上げていきたいと思います。

参考書籍

🍒 まとめ

輪読会が終わり、かれこれ3ヶ月も経ってしまいましたが、第16週目のブログを書きました。

1週目をスタートしたときから「最終週まで書き上げる!」と自分の中で目標を決めていたので、今更ですが書いてみました。次は最終週です!

では、また!(次回、第17週目(最終週))

DateオブジェクトのgetMonth()メソッドは、JSTを基準とした値を返す

出典: いらすとや

はじめに

JavaScriptでは、Dateオブジェクトから、指定したその月の最終日(月末日)を取り出す際、getMonth()メソッド を利用します。

上記の一文だけ読むとそんなに難しいことではない気がするのですが、実際にやってみて、JavaScript独特のDateオブジェクトの挙動に翻弄され、ハマりまくってしまいました。

JavaScript の Dateは、初心者がハマりがちな罠が多いそうです。

何だか面倒な挙動が多く「クセが強い!」Dateオブジェクト。

そんな同じ状況でハマってしまう方の助けになればと思いブログに書き留めておきます。

前提知識

UTCGMTJSTの違い

まず、前提としてDateオブジェクトはUTC協定世界時)を基準としています。

UTCの前は、GMTが世界の標準時でした。

  • GMTの特徴
    • 英国のグリニッジ天文台(経緯0度)での地方平均時(平均太陽が南中する時を正午とする)のことで、天文観測(地球の自転)によって決められる時刻
    • UTCとほとんど同じだが、現在はUTCのほうがより正確であるため、そちらを世界標準として採用している
    • グリニッジ標準時 - Wikipedia

それから、UTCの時刻へ9時間プラスした時刻をJSTと呼びます。

ISO 8160

それから、日付と時刻の表記に関する国際規格に沿って、形式や表記が定められています。

以下、返り値として返される、2021-10-31T11:31:04.554Zや、2021-10-30T15:00:00.000Zという表記も、ISO 8160に準じて定められています。

ISO 8601 - Wikipedia

ハマってしまったこと

Dateオブジェクト

developer.mozilla.org

まずは、Dateオブジェクトを作ってみます。 Date.now()メソッドを使い、現在時刻(UTC)を生成することができます。 ここでは、「UTC」であることがポイントです。

> now = new Date();
2021-10-31T11:31:04.554Z

ここから、その月の最終日を取得するために、以下の引数を渡してあげます。 第三引数に0を渡すと、その月の最終日が返ってくるはずですが…

date = new Date(年, 月, 0);

date = new Date(2021, 10, 0);
2021-10-30T15:00:00.000Z

あれ? 10月30日で最終日ではない…

10月は、31日まで存在しますが、10月30日となっています。

UTCだから、おかしなことになっているのではないかと考え、JSTに変換するメソッドがないか調べてみました。

toLocaleString()メソッド

developer.mozilla.org

ありました。

このメソッドを使うことでJSTへ変換できるようです。

.toLocaleString({ timeZone: 'Asia/Tokyo' })

> now = new Date().toLocaleString({ timeZone: 'Asia/Tokyo' });
'2021/10/31 21:10:38'

出来ました! 現在の日本時刻(21:10)と同じです。

このオブジェクトを使って、今回やりたかったこと(その月の最終日を取得する)試してみます。

まずは、UTCでその月の最終日を取得します。

> const date = new Date(2021, 10, 0);
undefined
> date
2021-10-30T15:00:00.000Z

ここから、変数dateに対してメソッドを実行してみます。 結果、無事に10月31日と表示されました。

> date.toLocaleString({ timeZone: 'Asia/Tokyo' });
'2021/10/31 0:00:00'

toLocaleStringメソッド は、文字通り String(文字列)に修正してしまうものなので注意

ここで本題のgetMonth()メソッドを使い、指定された日時の「月」だけ取得を試みてみます。

> const date = new Date(2021, 10, 0);
undefined
> const endDate = date.toLocaleString({ timeZone: 'Asia/Tokyo' });
undefined
> endMonth = endDate.getMonth();
Uncaught TypeError: endDate.getMonth is not a function

ん? Uncaught TypeError: endDate.getMonth is not a function、値を関数として呼び出そうとしたが、その値が実際には関数ではなかった場合に発生するエラーが返ってきました。

これは小見出しにもあるように、「toLocaleStringメソッド は、文字通り String(文字列)に修正してしまうもの」なので、変数endDateに代入されている値は、Stringなので、レシーバとしては適切ではないようです。

getMonth()メソッドに対しては、Detaオブジェクトを利用する必要があるようです。

以上、私がハマった経緯になります。次に解決方法をまとめます。

結論

ここからは、ハマったポイントを抜け出した結論になります。

正直、結論は「え?そんなことだったの…」と、拍子抜けの内容です。 しかし、上記のDateオブジェクトの挙動のクセを体感したからこその拍子抜けなので、今回は遠回りでしたがとてもよい経験となりました。

DateオブジェクトのgetMonth()メソッドは、JSTを基準とした値を返す

MDNには、以下のように書いていました。

注: Date オブジェクトの中心となる時間値は UTC ですが、日付と時刻、またはその一部を取得する基本的なメソッドは、すべて地方時 (ホストシステムなど) のタイムゾーンとオフセットで動作することを覚えておくことが重要です。

要は、DateオブジェクトのgetMonth()メソッドJSTとして返事をくれるようです!!

一点、注意点としては、0-11の数字で扱っているので、正確な月に修正するには +1 が必要です。

変数dateへ、10月の最終日(31日)のオブジェクトを生成して代入します。

確認してみると、UTCでは、2021-10-30T15:00:00.000Z と表記されています。

> const date = new Date(2021, 10, 0);
undefined
> date
2021-10-30T15:00:00.000Z

では、ここで「getMonth()メソッドJSTとして返事をくれる」が正しいか試してみます。

> date.getMonth();
9

「9」!

無事に9が表示されました!!!

上述しましたが、0-11の数字で扱っているので、9は、10月のことになります。

ちゃんとJSTとして変換して返してくれています。

おまけ

諸々が解決したあと、改めてMDNを読み直してみました。

すると、以下のように「地方時に基づき」と書いてありました…汗

地方時 == 日本の時刻 ですね。

getMonth() メソッドは、地方時に基づき、指定された日付の「月」を表す 0 を基点とした値 (すなわち 0 が年の最初の月を示す) を返します。

developer.mozilla.org

何だか今日は、JavaScriptのトリックに翻弄された一日でした…(JavaScriptにそんなつもりは無いと思いますが…)

引き続きドキュメントをしっかり読み解き、ひとつひとつやっていきたいと思います。

ハッピーハロウィーーン!!

チェリー本輪読会 第15週目まとめ

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本輪読会の第15週目のエントリーになります。

輪読会の概要については第1週目にまとめています。

🍒 輪読会 第15週目まとめ

第10章10.1.1〜第10章10.6まで

期間:2021年08月30日〜2021年09月3日

yield とは

ブロックを引数として受け取り、展開するためにyieldを使います。

ここでいうブロックは、do〜endの処理の中身を指します。

yieldとは、受け取ったブロック引数を展開するしくみです。do〜endの中身を受け取り処理しています。

def playing
    puts 'guitar'
    yield
end
=> :playing

playing do
    puts 'bass'
end

#=> guitar
#=> bass
    

ブロックを引数として受け取る

引数名の前に&を付けることで、ブロックをメソッドの引数として受け取ることができます。

def playing(&block)
    puts 'I play guitar!!'
    sound = block.call('ギュイイイーーーン!!!')
    puts sound
end

playing do | sound |
    sound * 2 
end

#=> I play guitar!!
#=> ギュイイイーーーン!!!ギュイイイーーーン!!!

&blockの「&」って?

&blockの&は、引数にブロックが渡ってきた際に、Procオブジェクトへ変換する役割があります。

qiita.com

ブロックを引数にするメリット

ブロックをほかのメソッドに引き渡すことができます。

def playing_guitar(&block)
    sounds = ['ギュイーン', 'ガガガッ', 'ジャラーン']
    playing_tech(sounds, &block)
end

def playing_tech (sounds, &block)
    puts sounds[1]
    puts block.call(sounds[0])
    puts sounds[2]
end

playing_guitar do | sound |
    sound * 3
end

#=> ガガガッ
#=> ギュイーンギュイーンギュイーン
#=> ジャラーン

callメソッド

docs.ruby-lang.org

Proc とは

Procは、Procedureから来ています。プログラミングにおいて複数の処理をひとつにまとめたものです。手順、手続き。一連の処理を意味を持った一まとまりにすることで、再利用性が高まり、プログラム中に繰り返して現れる処理を一ヶ所で記述でき、プログラムの管理を容易にするしくみです。

ja.wikipedia.org

Procクラスは、ブロックをオブジェクト化するためのクラスです。ブロック、つまり「何らかの処理(何らかの手続)」を表します。Procオブジェクトを実行したい場合は、callメソッドを使います。

shout = Proc.new { 'Hey!Ho!Let\'s go!' }
#=> #<Proc:0x00007fd79c995248 (irb):1>

shout.call
#=> "Hey!Ho!Let's go!"

Proc.newとラムダの違い

-> または、lamdaメソッドで、Procオブジェクトを作ることができます。このような呼び出しで作成したProcオブジェクトを「ラムダ式」と呼びます。

単純な呼び出しでは、Proc,newもラムダも引数の扱いに違いはありません。

add_lambda = ->(a, b) { a + b }
add_lambda.call(100,500)
#=> 600

add_lambda = lambda { |a, b| a + b }
add_lambda.call(10,50)
#=> 60

しかし、ラムダの場合はメソッドの呼び出しと同じように引数の数に過不足があるとエラーが発生します。ラムダの方が引数のチェックが厳密になります。

add_lambda = lambda { |a, b| a + b }
add_lambda.call(10, 20, 30)

# エラーが発生。引数がひとつ多い。
wrong number of arguments (given 3, expected 2) (ArgumentError)

[1, 2, 3].map(&:to_s)イディオム

AtCoderなどでよく使っているイディオムです。

以下、map(&:upcase) と書くことで、Procオブジェクトに変換し、mapメソッドにブロックとして渡すことができます。

[ 'guitar', 'bass', 'drums' ].map { |s| s.upcase }
#=> ["GUITAR", "BASS", "DRUMS"]

[ 'guitar', 'bass', 'drums' ].map(&:upcase)
#=> ["GUITAR", "BASS", "DRUMS"]

Rubyの公式リファレンスが読めるようになる本

zenn.dev

9月3日にZenで公開された伊藤さんの本を読みました。

とても良かったです!

当時は、るりまに書かれていることが「意味がwakaran」の連続で、相当苦しめられました…。

冒頭の説明にもあるように、「ネットの技術記事より公式リファレンスを読め!」とよく指摘されていたましたが、そのるりま自体の意味わからんのですが....と、ずーっと思っていました。

今は、輪読会やプラクティス等で試行錯誤し取り組んできたおかげで、るりまが少しづつ読めるようにはなってきましたが、当時この本で事前に学べていたら、るりまとの向き合い方が全然変わっていたと思いますし、学習効率の向上や必要ない遠回りをせずに済んだと思います。その当時に思い悩んで詰まっていたポイントの解説が満載で、初心者には間違いなく救いの本となると思います。

今からRubyを始める方には、ぜひとも読んでいただきたい!

そんな一冊です!!

参考書籍

🍒 まとめ

だいぶ間が空いてしまいましたが第15週目のブログを書きました。

残り2週!

では、また!(次回、第16週目)

初めてのLT会 Vol.9 感想

LT会に参加しました!

10月9日(土曜)、フィヨルドブートキャンプ内で開催されたLT会へ参加してきました!

今回のテーマは「しくじりから学んだこと」

登壇者7名の皆さんの発表がどれもすごく良かったので感想をブログに書いてみました。

LT会はやる側も見る側も得るものがとても多いです。

まだ参加されたことがない方や、登壇されたことがない方の参考になれば幸いです。

@fuga__chさん

フィヨルドブートキャンプ(以下、FBC)のプラクティスの山場でもある「チーム開発」

自分は少し先のプラクティスではありますが、周りから話しを聞いている限り、「やってけるのか?レビュー受けるのは経験あるが、レビューするとか無理じゃない?」と、不安しかありません。そんな不安をふーがさんはどのように捉えて乗り越えていったのか?今回のLTではそんな貴重な経験談を聞くことができました。間違いを恐れずに、チームメンバーに頼ることの大切さ、今回のLTを聞き、不安が和らぎ楽しみに変わってきました。早くチーム開発したい!!

speakerdeck.com

@Maedaさん

終わらないマラソン…。すごくわかります。自分も隅々まで理解しなければならない。という思いが強い方なので、パラシュート勉強法を意識し、コミュニティを活用していきたいと思いました。プログラマを目指す以上、技術についてのマラソンは終わることありません。それなら、楽しく自分のペースで走り続けたいと思いました。

ある文系プログラマがテックリードを任されるまでに学んだこと ── 最前線で生き延びる4つの戦略 - エンジニアHub|Webエンジニアのキャリアを考える!

speakerdeck.com

@Shugo さん

侘び寂びの効いた素敵なLTでした。タイトルの「休む、」の「、」がなんか好きです。内容もスライドと話の展開もあいまって惹きつけられました。べきべき思考はすごく共感。認知の歪みだと意識して対応していきたいと思いました。最近観た「おつかれシャワー」ともリンクして「休む、」の大切さが沁みました。。。。

#178 メンタル不調の体験談 - YouTube

speakerdeck.com

@haruguchiさん

「孤学」

自分もひとりで学習しているときに限界を感じ、それからFBCに参加した経緯があり、とても共感できるLTでした。当時、自分では「独学」だと思っていましたが「孤独」だったとは…。(独学大全読み返したいと思います)

独学大全 | 書籍 | ダイヤモンド社

現在、haruguchiさんとは輪読会でご一緒してますが、説明が論理的でわかりやすく、いつも助けてもらっています。声馴染みという表現も素敵でした。これからもよろしくお願いします!

speakerdeck.com

@Aseiideさん

直前までスライド作成していたとは思えない安定感抜群の発表でした。しかも明日もLT出るとは凄すぎる!

kaigionrails.doorkeeper.jp

GitHubのissueの機能は知りませんでした。早速使ってみようと思います。タスクの分解を解像度と表現されているのがわかりやすかったです。自分はタスク分解が下手なので、今回の内容でもあった粒度を常に意識して取り組んでいきたいと思いました。

ideさんは輪読会など、普段から話す機会も多いのですが、話す内容の構成が論理的でとても分かりやすく尊敬します。明日も頑張ってください!

speakerdeck.com

N4be さん

LT後の雑談タイムでは楽しくおしゃべりでき盛り上がりました。しかし、そこでの印象が強くLTの内容が思い出せません…w

そんな明るく素敵なN4beさんは、大学とも並行してFBCも器用にこなされている印象だったので、今回のようなしくじりは意外でした。「プラクティスをどんどん進めたい」という誰しもがかかる悪魔の呪いに立ち向かっていくために「面倒くさがらない、本読もう、公式文書を読もう。」みんな失敗から学んで成長しているんですね。

ビール片手にN4beさんとしくじり話を語り合いたくなる、そんな素敵なLTでした!

Prost!!

speakerdeck.com

@napple29さん

当時を思い返すとSSH接続のプラクティスに取り組んでいるとき、マジわからん‥‥の連続でした。本当ツラかった。。。「全くわからないことがわかった経験が自信になった」これは完全にわかりみでした。自分もわからない経験を乗り越え、その度に自信になり今も続けられていますが、わからないままで終わらなかったのは、FBCのおかげです。

冒頭で「初心を思い出す系LT」とありましたが、いつでもこの初心を忘れないようにしたいと思える、そんな素敵なLTでした!

speakerdeck.com

主催の@siroemkさん

LT会の主催お疲れさまでした!

とても楽しく学びの多い会でした。 ぜひ今後はTシャツ作りましょう!w

チェリー本輪読会 第14週目まとめ

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本輪読会の第14週目のエントリーになります。

輪読会の概要については第1週目にまとめています。

🍒 輪読会 第14週目まとめ

第9章9.1.1〜第9章9.7まで

期間:2021年08月23日〜2021年08月27日

エラーとは

プログラムの処理中に発生するエラーにはいくつか種類があります。

  • データのエラー((広い意味で)データの誤り。構造上の間違いなど)
  • システムのエラー(ハードディスクが故障、回線が切断など)
  • プログラミングのエラー(メソッド名、引数が存在しない、間違っているなど)

上記のようなさまざま状況で発生するエラーですが、プログラムを正常に戻し処理を続けるには、エラーの原因を取り除く必要があります。その際に役に立つのが「例外」という仕組みです。

Rubyには、エラー処理をサポートするための「例外処理」の仕組みが備わっています。

例外(Exception)とは

wikipediaには以下のように書いています。

プログラミングでは、プログラムがある処理を実行している途中で生じ得る、設計から逸脱した状態を「例外」という。

例外 - Wikipedia

ここでは、地震、落雷により急にパソコンのハードウエアが壊れてエラーが起きるような、想定が困難な状況ではなく、「メソッド名の定義がおかしい。変数に誤った値が格納されている、タイポしている等」予め発生する可能性があると思われる、想定しているエラーのことを指しています。通常、例外は何らかの理由により処理が中断され、その状況に関する情報が通常とは異なる経路で送出されます。

例外処理とは

エラーが起きたときに行う処理のことを例外処理と呼んでいます。プログラムの実行中にエラーが起こると、プログラムは一時中断し「例外処理」を探しそれを実行します。

仮に、以下のファイルを用意し実行してみました。敢えて、行末のメソッドで呼び出すことができない引数を渡しています。

# fizz_buzz.rb

def fizz_buzz(n)
  if n % 15 == 0
    'Fizz Buzz'
  elsif n % 3 == 0
    'Fizz'
  elsif n % 5 == 0
    'Buzz'
  else
    n.to_s
  end
end

fizz_buzz(foobarbaz)

結果、プログラムが一時中断し「例外処理」が出力されます。

❯ ruby fizz_buzz.rb
fizz_buzz.rb:13:in `<main>': undefined local variable or method `foobarbaz' for main:Object (NameError)

例外処理もオブジェクト

上記の例外処理では、NameErrorとなり、「定義されていないローカル変数またはメソッドなので、エラーですよ〜」と怒られています。この例外処理は、NameErrorクラスのオブジェクトになります。

NameError(未定義のローカル変数や定数を使用したときに発生します。)

class NameError (Ruby 3.0.0 リファレンスマニュアル)

例外クラス(るりま)

例外も例外クラスのインスタンス(オブジェクト)なので、るりまに情報がまとめられています。

library _builtin (Ruby 3.0.0 リファレンスマニュアル)

例外処理が発生した場合、るりまを読んでも具体的な解決策がわかないことが多いです。その際は、適切なキーワードを元に(エラー文など)解決策をググって見つけた方が早いです。(個人的意見)

例外を捕捉して処理を実行する

何らかの理由で例外が発生してもプログラムを続行したい場合は、begein 〜 rescue 〜 end と、記述することで、プログラムを続行させることができます。

# 構文

begein
    # 例外が起きうる処理
rescue
  # 例外が発生した場合の処理
end

実際に試してみました。

puts '演奏開始'

module BassGuitar
    def play(bassist)
        puts "#{bassist}: ブン!ブン!"
    end
end

begin
    bass_guitar = BassGuitar.new('ジャコ・パストリアス')
rescue
    puts '機材トラブルが発生したが、このまま演奏を続行する'
end

puts '演奏終了'

この処理を実行してみると...

# 処理結果
演奏開始
機材トラブルが発生したが、このまま演奏を続行する
演奏終了

「演奏開始」を出力し、その後、begin以下で「例外が起きうる処理」を書いていますので、rescue以下で、「機材トラブルが発生したが、このまま演奏を続行する」がputsで出力されました。その後の「演奏終了」まで無事出力されたので、最初から最後までプログラムを実行できたことになります。

例外オブジェクトから情報を取得する

例外オブジェクトから情報を取得することも可能です。

# 構文

begin
    # 例外が起きうる処理
rescue => 例外オブジェクトを格納する変数
    # 例外が発生した場合の処理
end

rescue => e として、変数に例外オブジェクトを格納することができます。変数eは、exception(例外)から来ています。

例外オブジェクトへメソッドを使うことで、エラーメッセージmessageメソッドを返したり、バックトレース情報backtraceメソッドを返したりすることができます。

module BassGuitar
    def play(bassist)
        puts "#{bassist}: Bom!Bom!"
    end
end

begin
    bass_guitar = BassGuitar.new('ジャコ・パストリアス')
rescue => e
    puts "エラークラス: #{e.class}"
    puts "エラーメッセージ: #{e.message}"
    puts "バックトレース: #{e.backtrace}"
    puts "---------------------------------"
end

この処理を実行してみると...

# 処理結果
エラークラス: NoMethodError
エラーメッセージ: undefined method `new' for BassGuitar:Module
バックトレース: ["(irb):27:in `<main>'", "/Users/shiro/.rbenv/versions/3.0.2/lib........(省略)
---------------------------------

変数eへ格納した例外オブジェクトの情報を出力することができます。

意図的に例外を発生させる

例外は捕捉するだけではなく、コードの中で意図的に発生させることもできます。

その際に使用するのが、raiseメソッドです。

チェリー本のプログラム例を試してみました。(9.3 「意図的に例外を発生させる」チェリー本341頁)

def currency_of(country)
 case country
    when :japan
      'yen'
    when :us
      'dollar'
    when :india
      'rupee'
    else
      raise
  end
end

# 実行結果
currency_of(:italy)
(irb):24:in `currency_of': unhandled exception
  from (irb):27:in `<main>'
  from /Users/shiro/.rbenv/versions/3.0.2/lib/ruby/gems/3.0.0/gems/irb-1.3.5/exe/irb:11:in `<top (required)>'
    from /Users/shiro/.rbenv/versions/3.0.2/bin/irb:23:in `load'
  from /Users/shiro/.rbenv/versions/3.0.2/bin/irb:23:in `<main>'

???

エラーメッセージにunhandled exception と出てしまいました。

チェリー本とるりまには、特定の例外クラスに該当しないエラーが起こった場合はRuntimeErrorが発生すると書いてあるが、なぜ?

質問してみました

伊藤さんから回答いただきました。

どこかのタイミングで表示が変わったようです。以下のように記述すると、RuntimeErrorを出すことができました。

def currency_of(country)
  case country
  when :japan
    'yen'
  when :us
    'dollar'
  when :india
    'rupee'
  else
    raise
  end
end

begin
  currency_of(:italy)
rescue => e
  p e
end

# 実行結果
RuntimeError

例外処理のベストプラクティス

  • 例外処理のセオリー
    • 例外が発生したら即座に異常終了させよう
    • フレームワークの共通事項に全部丸投げしよう

安易にrescueせずに、フレームワークに備わっている例外処理の仕組みに処理を委ねるのがセオリーです。実際にrescueすべきケースに遭遇した時、今回の件を改めて見直し対応を検討するのが、初心者の内はベストプラクティスだと思いました。

RubyMine入門

zenn.dev

フィヨルドブートキャンプ受講生の@ikumatdkrさんが、Zennで出版されたRubyMineの入門書です。

RubyMineを使い始めたばかりの方、基本操作は覚えたんだけどさらなる便利機能を覚えたい方、ぜひとも一度読んでいただきたい内容です。

僕もRubyMineを使い初めて3ヶ月目ごろに読みましたが、知らない内容や知ってはいたが使いこなせていない内容が盛りだくさん、かつ親切丁寧に説明されており、非常に勉強になりました。

RubyMineは、ググっても詳しく丁寧に説明されている情報があまりありません。また公式ページも細かい説明までは載っていなく、RubyMine初心者にとっては、まず最初に読むべきベストな一冊だと思います!!

しかも無料!@ikumatdkrさん、ありがとうございます〜!

参考書籍

🍒 まとめ

今週は例外処理編でした。

例外処理のベストプラクティスに書いたように、まずはフレームワークに従うのが良いとは思いますが、裏側で起こっている処理の仕組みを知ることができ勉強になりました。

次は、yield、Procについて書きたいと思います。

では、また来週!(次回、第15週目)

あんちぽさんトークイベント感想

先日、フィヨルドブートキャンプ内でトークイベントが開催されたのですが参加してきました!

スペシャルゲストとして、GMOペパボ株式会社 取締役CTO CTO室室長の栗林 健太郎さんを招いての、まさにスペシャルな最高の夜でした。

またなんと!運良くトークイベント後の交流タイムには、直接お話しすることもできました。

当初、個人の日報に書こうと思いましたが、思ったより長文になってしまったため…。 せっかくなので、ブログに書きたいと思います。

tech.pepabo.com

注:以下はあんちぽさんの意見はこうだった。ということではなく、トークイベントや直接お話しをお伺いする中での僕の解釈、感想になります。

イベントのスライド

speakerdeck.com

キャリアキーノート

以前に一度スライド等を拝見したことはあったのですが、直接キャリアキーノートについてのお話しを聞け興味深かったです。

過去、ペパポさんで働いている方のお話しを伺う機会が何度かあったりしたのですが、皆さんそれぞれ自分自身の軸(価値観)をしっかり持っておられる方が多い印象で、言語化の凄さも相まってか強く印象に残っています。それもこのような取り組みが影響しているのかなと感じました。

僕の直近の課題は、能力(プログラミングスキル)を得ることが最優先ではありますが、価値観を中心とした内的キャリアについての大事さを考えさせられました。

blog.hifumi.info

speakerdeck.com

他人の人生を生きない

そのつもりはなくても、つい他人の人生と自分の人生を比較し落ち込んだり...。 他人が決めた人生に勝手に憧れ、勝手に失望しているのは自分なんですが、こういった考えも自分の価値観がブレているせいであることが理解できました。これは人それぞれだとは思いますが、僕自身は上手くいかないことが続くと価値観がブレてしまうことが多いので「おい!今、他人の人生生きてるよ。危険だよ。」と気づけるように注意していきたいです。

欲望の三角形の話しは初めて聞きましたが勉強になりました。こういったことを知り意識するだけでも全然違うなと思いました。

rinnsyou.com

「逃げ切り」マインド

生存者バイアスからの「逃げ切り」マインドのお話しも面白かったです。

「逃げ切る」ということを考えたことはないですが、確かに最近耳にすることが増えたフレーズだと思いました。Fireとかもその関係から派生した言葉なんですかね?もちろん、お金に困る生活はしたくないですし、働かずとも十分な収入を生むことができる仕組みを持つことは素晴らしいと思います。Fire自体は経済的に自立し、そこから逃げるわけではなく、自由に何かに挑戦していくことなのかもしれませんが、早期リタイアという言葉が絡んでくるので、何かモヤモヤしますね。

Fireについては、このnoteが面白かったのでご紹介。

comemo.nikkei.com

いずれにせよ、個人的な思いとしては健康でい続けれる限り、逃げ切りマインドではなく、追い続けたい(仕事も含めて)と思っています。死ぬまで自分の価値観を元に、やりたくてしかたがない(必然性)そんな仕事ができたら最高です。

Unknown unknowns

普段、何も考えず生きていると、つい「Known, Knowns」になりがちだなと思いました。

「Unknown unknowns」のような事柄にも、勇気を持って踏み出せるように心がけたいです。

ちょっと違うかもしれませんが、新商品が出たら買ってみたり、普段行かない道を通ってみたり、小さなことですが出来ることから行動しようと思いました。それから、仕事や人生の大事な場面でも「Unknown unknows」を楽しめる自分でいたいです。

自分を小さな価値観に矮小化するぐらいなら自分を放り捨てる

少し耳の痛い話でした。

捨てたいんだけど捨てられない。そんな僕にとっては必要ないはずの価値観に固執することがあります。とくに無意識だったり、いろいろと心に余裕がないと、その必要ない価値観が出てきて邪魔をしてきます。そんなもの捨ててしまえ!と、わかってはいるんだけど捨てられない。「必然性」の話しもされていましたが、僕にとっての必然性のレベルが、まだまだ低いのだと痛感しました。これは、僕に取っては簡単な問題ではないですが、今回の話しも参考に考えていきたいと思いました。

紹介されていた書籍

books.bunshun.jp

www.chikumashobo.co.jp

面白そうで早速購入してみました。 読書についてのお話しもお伺いしたのですが、定期的に書店に足を運ばれ、上から下まで新書をチェックされているそうです。「Amazonなどはその人の興味に合う本を紹介してくるのでなかなか新しい本との出会いが少ない。書店へ出向くことで新しい出会いがある。」たしかに。納得です。

ベーシックなスキル

ベーシックなスキルについて「非常に変わりにくい部分」が重要という話しもありました。

  • 変わりやすい -> 変わりにくい
  • 具体的 -> 抽象的

自分のイメージだとこんな感じです。

(これが合ってるかはわかりません。今現状の自分の解釈です)

三角形で表すと、頂点に近づくと抽象的な物事で、逆に底辺に近づくとより具体的な物事なイメージです。それぞれが分断されているというわけではなく、つながりをもって存在しているイメージです。オブジェクト指向の継承みたいなことなのかなと思いました。

非常に変わりにくい部分は、より抽象的な物事で実体として理解しづらいです(知能、創造性、概念的能力…)。実際にこの能力を伸ばすためには具体的に何をすればいいのか?ハッキリとはわかりませんが、価値観を育てることが、ベーシックなスキルの助けになることは理解できました。

しかし、これも本を読んだり、自分で考えたり、経験してみたり、普通のこと(以下で書いてみました)を継続してやり続けるしかないのかなと思いました。プログラムを書く前に行うタスクばらしのように、具体的な物事に小さく切り分けてみたり、それからクラスやメソッドなどで、抽象的な物事としてひとつにまとめたりするように、具体と抽象を行ったり来たりしながら、さまざまな物事をプログラミングと同じく当てはめて考えていけるようになることが大事なのかなと思いました。

扱うテーマの選択は大事ですが、重要なベーシックなスキル取得への道は、地道な抽象・具体の行動の積み重ねしかないのかなと思いました(近道はない)。

普通のことをちゃんとやる

あんちぽさんの今までの経歴ややってきたことを見聞きしていると、何か特別なことをしてきたんではないかと思うこともあります。しかし、超人にしかできないような特別なことはなく、本を読んだり、興味のあることにとことんハマってみたり、自分の価値観をベースに淡々と積み上げられてこられたんだなという印象でした。結局は、普通のことをちゃんとやる。プログラミングなら技術書を読む。コードを書く。何か作ってみる。そこに、価値観の幅を広げ育てていき、興味が変わったら方向を変えてもいいし、辞めてもいいし、それからまた戻ってきてもいい。小さいことを積み重ねていくことが大事なんだと感じました。しかし、話しを聞いてる分には簡単そうに聞こえはしましたが、実際のところは人の何倍も努力し試行錯誤し、またチャレンジし続けているんだろうなと思いました。多くのさまざまな経験の中から語られているだろうその言葉は何だか重く厳しさも感じました。

コミュニティ

コミュニティに関する考え、関わり合いについてもお伺いできました。 フィヨルドブートキャンプでは、Discordをメインにコミュニティが築かれているのですが、量、質ともにそこで得られるものがとても大きいことを改めて感じました。卒業生の方とお話しする機会もありますが、どんどん良くなっているフィヨルドブートキャンプの話しを聞く度に、良いタイミングで関われたことはとても幸運です。

そんなお話しを聞きながら、コミュニティについては、以下、高橋征義さんの記事を思い出したりしました。 これからも、フィヨルドブートキャンプに限らず、コミュニティへ積極的に関わっていきたいと思いました。

magazine.rubyist.net

やりたくねえことやってる暇はねえ

トークイベント後、価値観について考えていたときマーシ―の言葉を思い出しました。

ザ・クロマニヨンズ真島昌利が、当時ザ・ブルーハーツというバンドで「やりたくねえことやってる暇はねえ」と歌っている曲があります。10代の頃初めて聴いたとき「うぉ!カッコいい!」となりましたが、だいぶ大人になった今でも、僕の価値観のベースが変わらないでいることが少し嬉しかったりしました。

しかし、それにしても人生は短い。

THE BLUE HEARTS ブルースをけとばせ 歌詞 - 歌ネット

何かをやるためには、ついでにやらなければいけないことがある

しかし、やりたくねぇからやらない。ではダメなこともわかっています。 社会に出ていろいろと経験していくなかで、「何かをやるためには、ついでにやらなければいけないこと」があることも学んできました。大きなことで言えば日本に住みたいのであれば、税金を収める必要がありますし、法律というルールに従う必要があります。会社でやりたいことがあれば、上司からの了承を得るためにやならければいけないこともあるかもしれません。何かやりたいことがあるのなら、それに付随するやらなければいけないことにも、しっかりと向き合いクリアしていく必要があります。

これまた大好きなザ・クロマニヨンズ甲本ヒロトが上記のことをインタビューで答えているのを見つけたので紹介しておきます。

hazamamakoto.blogspot.com

自分のやりたいことを本気でやっている人はカッコいい

何だか話しが脱線しましたが…

最後に。

価値観が変わり続ける世の中で、自分の価値観を軸にブレずに自分のやりたいことを本気でやっている人はカッコいいと思います。

能力(向き不向きとか)動機(生活のため、お金のためとか)そんなのカンケイない。自分の価値観を信じてやりたいことやって生きていく。そうできると信じていた10代の頃。しかし、失敗や挫折を繰り返し、厳しい現実に直面すると、そんな甘いこと言ってられない、ちゃんとしなきゃと、他人と比較し落ち込んだり、歳を重ねるにつれて価値観がブレブレになる自分がいました。 そんなこんなで葛藤しながらも、ようやく今は自分の価値感を多少は取り戻し、やりたいことをやれてはいますが、そこで何も結果が残せていない以上、これから先の将来に不安が多いのも事実です。

今回のトークは、そんな心情ともマッチしとても胸に響きました。

また最近、目の前の目標(卒業して就職すること)ばかりに執着し、冒頭のキャリアキーノートのように自分の価値観を俯瞰して見ることが少なかったのですが、今回のイベントを通して、自分の価値観について考えるとてもよい機会にもなりました。

長々と思うことを好き勝手に書いてしまいましたが、今回このようなトークイベントに参加できたことを嬉しく思います。

あんちぽさん、また関係者の皆さま、ありがとうございました!!

チェリー本輪読会 第13週目まとめ

f:id:shirotamaki:20210619091936p:plain

🍒 はじめに

チェリー本輪読会の第13週目のエントリーになります。

輪読会の概要については第1週目にまとめています。

🍒 輪読会 第13週目まとめ

第8章8.1.1〜第8章8.10まで

期間:2021年08月16日〜2021年08月20日

モジュールの概要

クラスは、データとメソッドを持ったオブジェクトを扱う機能ですが、モジュールは「処理の部分だけ」をまとめた機能になります。

以下の特徴があります。

  • モジュールは、クラスのようにインスタンスを持つことはできません。
  • 他のモジュールやクラスを継承することはできません。

モジュールの使い方(Mix-in)

モジュールをクラスに混ぜ合わせて使えるようにすることをMix-inといいます。

以下、Mix-inの手法を説明します。

include

モジュールをクラスに取り組むことをincludeといいます。クラスに取り込むことで、モジュールで定義したメソッドがインスタンスメソッドとして呼び出せるようになります。

以下の例では、モジュールでEffectorを作成し、Guitarクラスにincludeしてみました。Guitar.newでインスタンスを生成し、メソッドを呼び出すことができます。Guitarをplayしchalkさせるのですが、引数にジミヘンを渡すことで、ジミヘンにしか出せない強烈なファズサウンドを出力することができます。

module Effector
    def chalk(guitarist)
        puts "#{guitarist}: ギュイーーン!!"
    end
end

class Guitar
    include Effector
    
    def play
        chalk('ジミヘンドリックス')
    end
end

# インスタンスメソッドとして呼び出す。
sound = Guitar.new
sound.play
ジミヘンドリックス: ギュイーーン!!  

extend

モジュールをクラスにMix-inするもうひとつの方法です。モジュール内のメソッドをそのクラスのクラスメソッドにすることができます。

今度は、GuitarクラスへEffectorモジュールをextendすることで、クラスメソッドとして呼び出すことが可能になります。

module Effector
    def chalk(guitarist)
        puts "#{guitarist}: ギュイーーン!!"
    end
end

class Guitar
    extend Effector

    def self.play
        chalk('ジミヘンドリックス')
    end
end

# クラスメソッド経由で呼び出す。
Guitar.play
ジミヘンドリックス: ギュイーーン!!

# Guitarクラスのクラスメソッドとして呼び出す。
Guitar.chalk('ジミヘン')
ジミヘン: ギュイーーン!!

Enumerableモジュール

docs.ruby-lang.org

このモジュールのメソッドは全て each を用いて定義されているので、インクルードするクラスには each が定義されていなければなりません。

上記は、るりまに記載されているの内容ですが、最初読んだとき「全てeachを用いて定義されている」の意味がわかりませんでした。輪読会内で質問をしてみたところ無事に理解できましたが、私と同じく疑問に思われている方の参考になればと思い私の解釈を書いておきます。

Enumerableモジュールに定義されたメソッドは、全て内部的にeachが動いています。Enumerableモジュールは、eachのみで書くことができる繰り返し処理を、より簡潔に書くために提供されている拡張機能のようなものです。

例えば、eachメソッドをundefすると、ブロックを渡したときに内部的に動くはずのeachが定義されていないことになるので動きません。逆に、自前のクラスにeachメソッドを定義すれば、Enumerableモジュールをincludeして50を超える便利なメソッドが手に入ることになります。

# Enumerableモジュールであるmapが使えなくなる。

class Hash
    undef each
end
=> nil

{a:1, b:2}.map
=> #<Enumerator: ...>

{a:1, b:2}.map{|k,v|[k,v*10]}
(irb):5:in `map': undefined method `each' for {:a=>1, :b=>2}:Hash (NoMethodError)

また、each以外のメソッドにもEnumerableの機能を提供するために、ラッパークラスというものがあります。Enumerator を介することで、Enumerableの機能を利用することができます。

docs.ruby-lang.org

以前のブログでも取り上げましたのでリンクを貼っておきます。

チェリー本輪読会 第5週目まとめ - D IT Y

Comparableモジュールと <=>演算子(UFO演算子

docs.ruby-lang.org

比較演算を可能にする(値の大小を識別できるようにする)モジュールです。

Comparableモジュールのメソッドを使うための条件は、このモジュールをインクルードするクラスで、基本的な比較演算子である <=> 演算子を定義している必要があります。

<=> 演算子はその形状から「UFO演算子」とも呼ばれています。

2 <=> 1
#=> 1
# a > b として、aが大きい場合正の整数となる。返り値は1となる。

2 <=> 2
#=> 0
# 等しい数値の場合は、0を返す。

1 <=> 2
#=> -1
# a < b 1が小さい場合、負の整数を返す。

2 <=> 'abc'
#=> nill
# 比較ができない場合は、nill

これは、「a <=> bは、a>bなら1を、a==bなら0を、a<bなら-1を返すようにしよう。そしたら便利なはず!sortとかで使いやすいはず!」ということが目的で使われます。

もしUFO演算子がなかったら、以下のように書かなくてはいけなくなり大変です。UFO演算子は、簡潔に書くために用意された演算子になります。

p ary.sort do |a, b|
  if a.to_i > b.to_i 
    1
  elsif a.to_i == b.to_i
    0
  elsif a.to_i < b.to_i
    -1
  else
    nil
  end
end

また、文字列の大小比較は、バイト配列の大小を元に比較しています。

''.bytes     #=> [227, 129, 130]
'あいう'.bytes #=> [227, 129, 130, 227, 129, 132, 227, 129, 134]

'あいう' <=> ''
=> 1
'' <=> 'あいう'
=> -1

文字列の大小比較については、伊藤さんのこちらの記事が参考になります。

qiita.com

名前空間

大規模なプログラムや外部に公開するgemを作ったりするときに、クラス名の重複が問題になることがあります。そのとき役に立つのが、名前空間(ネームスペース)としてのモジュールです。モジュール構文の中にクラス定義を書くと「そのモジュールに属するクラス」という意味になります。これで、同名のクラスがあったりしても外側のモジュール名さえ異なっていれば、名前の衝突は発生しなくなります。

以下、私の好きなバンドをモジュールにしました。それからクラスは、これまた大好きな二人のJohnを定義してみました。モジュール名::クラス名とすることで、同名のクラス名の衝突を防ぐことができます。

module Thebeatles
    class John
        def initialize(second_name)
            @second_name = second_name
        end
    end
end

module Sexpistols
    class John
        def initialize(second_name)
            @second_name = second_name
        end
    end
end

Thebeatles::John.new('Lennono')
=> #<Thebeatles::John:0x00007fab2a139368 @second_name="Lennono">

Sexpistols::John.new('Lydon')
=> #<Sexpistols::John:0x00007fab2f034cd8 @second_name="Lydon">

モジュールに特異メソッドを定義する

クラスへMix-inせずにモジュール自身に特異メソッドを定義すれば、モジュール名.クラス名という形でそのメソッドを呼び出すことができます。これで、クラスメソッドのような使い方ができます。

モジュールはインスタンス化できない点がクラスと異なります。インスタンスを作ってなにか操作する必要がないものであれば、モジュールにしておいたほうが他の開発者に変な勘違いをさせる心配がありません。

以下、self.chalkとすることで、特異メソッドとしてメソッドを定義しています。特異メソッドは、特定のオブジェクトに紐づくメソッドのことです。チェリー本輪読会 第12週目まとめ - D IT Y

module Guitar
    def self.play(guitarist)
        puts "#{guitarist}: ギュイーーン!!"
    end
end

Guitar.play('ジミヘン')
ジミヘン: ギュイーーン!!

class << self を使って定義することもできます。

module Guitar
    class << self    
        def play(guitarist)
            puts "#{guitarist}: ギュイーーン!!"
        end
    end
end

Guitar.play('ジミヘン')
ジミヘン: ギュイーーン!!

Sinatraメモアプリ

チェリー本とは関係ないのですが、上記のRubyのコードでセックスピストルズを取り上げたこともあり、以前に開発したメモアプリのことを思い出しました。

Image from Gyazo

github.com

歴史に残る大名盤へオマージュを捧げ作成しましたw

open.spotify.com

今思えばそんなに難しくはないプログラムなのですが、当時はホントわからないことだらけで大変でした…。しかし、そう思えるのもチェリー本を学ぶことで、Ruby力が付いたことが大きいです。

参考書籍

🍒 まとめ

久しぶりのブログ更新になります。

ブログとタイムラグがありますが、実は輪読会は9月17日にフィナーレを迎えました!最終日の詳細は後日ブログに書きたいと思います。

今回が13週目になりますので、こちらのブログも残り4週となります。復習も兼ね、完走まで頑張りたいと思います!

では、また来週!(次回、第14週目)