LoginSignup
0
0

プロを目指す人のためのRuby入門を読んだ感想

Last updated at Posted at 2023-07-25

プロを目指す人のためのRuby入門(通称チェリー本)をやっと一通り読むことができましたため、読んでみて、良かったところや学んだこと、難しかったところを記載します!

良かったところ

文法の説明にとどまらず、ベストな使用タイミングについても説明がされている

例外処理の章で、raiserescueの文法的な説明だけではなく、例外処理を実装する際のベストプラクティスについても触れられていた点がとても良かったです😊

過去に文法的には理解できましたが、どのタイミングで学んだことを使用した方が良いのかが分からなかった経験がございましたが、本書ではそういったことは少ないのではと思います!

例外処理では安易にrescueを使用して、プログラムの処理を継続しない方がよいです。なぜなら、本来はプログラムが異常終了するものを継続して処理を動かしているため、そのことによってデータ構造をおかしくしてしまうことにより、2次災害が起きる可能性があるためです。そのため、rescueを使用せずに異常終了したら、その原因を調べて解決するほうが良いです。

人間でも同じことが言えますが、病気や怪我をしている状態で無理に体を動かそうとすると、患部以外の箇所も悪くなってしまうという状態です😩
そういった場合は、まず患部の原因を調べて、治してから活動した方が良いです。

それでも例外処理を実装する場合には以下の点を意識した方が良いです。

  • バックトレースログを出力させる。
  • エラーメッセージを出力させる。
  • エラークラスを出力させる。

後で例外が発生した場合に原因調査が必要になった際に情報がないと調査に時間がかかったり、例外の原因がわからない状況になってしまうからです。

過去に実務でエラーメッセージがでないエラーに遭遇したことが何度かありました。エラーメッセージがでる場合よりもエラーメッセージが出ない方が格段にエラー解決が大変ですので、メッセージは出しておいた方が良いですね😅


Rubyと他の言語との比較で説明がされていたこと

Rubyだけの説明にとどまらず、Javaのような他言語との比較で説明されていて、わかりやすかったです!
印象的だったのが、定数privateの説明です。
私自身、過去にJavaを使用していた経験がありますが、Javaだと一度定数に値を定義したら、その後は定数の値を変更できません。

Rubyの場合、定数でも値を変更できてしまいます😳
それって定数っていうんですかね?とも思ったのですが、、

以下に試してみた結果、ワーニングメッセージは出ますが、定数の中身は変わっております。

irb(main):015:0* HOGE = 1
=> 1
irb(main):016:0> HOGE
=> 1
irb(main):017:0* HOGE = 2
(irb):17: warning: already initialized constant HOGE
(irb):14: warning: previous definition of HOGE was here
=> 2
irb(main):018:0> HOGE
=> 2
irb(main):019:0> 

privateについてですが、こちらもJavaですと、クラスの中でprivateメソッドを定義した場合、呼び出せるのは同じクラス内のメソッドです。

一方、Rubyだとprivateメソッドを呼び出せるのは同じクラス内のメソッドだけでなく、サブクラス(子クラス)のメソッドからも呼びせます。

irb(main):102:1* class Food
irb(main):103:1*   private
irb(main):104:1* 
irb(main):105:2*   def name
irb(main):106:2*     'Delicious meals'
irb(main):107:1*   end
irb(main):108:0> end
=> :name
irb(main):109:0> 
irb(main):110:0> 
irb(main):111:1* class Sushi < Food
irb(main):112:2*   def to_s
irb(main):113:2*     "name: #{name}"
irb(main):114:1*   end
irb(main):115:0> end
=> :to_s
irb(main):116:0> 
irb(main):117:0> sushi = Sushi.new
=> #<Sushi:0x00007fa83a0616b8>
irb(main):118:0> 
irb(main):119:0> sushi.to_s
=> "name: Delicious meals"
irb(main):120:0> 

学んだこと

曖昧だった用語について理解を深められた

  • レシーバ
  • ミュータブル
  • イミュータブル

レシーバはインスタンスやオブジェクトとほとんど同じような意味で使われております。レシーバという言葉を英訳すると「受け取る人」ですが、何を受け取るなのか疑問でしたが、インスタンスメソッドを呼び出した際にインスタンスメソッドがインスタンスに対してメッセージを送っているため、レシーバと呼ばれているそうです🤔

ミュータブルは変更可能なという意味。以下のようにString型は破壊的なメソッドで破壊的な変更ができます。

irb(main):103:0> aaa = "testtest"
=> "testtest"
irb(main):109:0> aaa.upcase!
=> "TESTTEST"
irb(main):110:0>
irb(main):111:0> aaa
=> "TESTTEST"
irb(main):112:0>

一方、イミュータブルは変更不可能なという意味。Integer型はString型のように破壊的な変更ができません。

例外処理でresucueした例外を再度発生させる

実務の中でよく以下のようなコードを見かけますが、本書を読むことでちゃんと理解できていないことに気づきました、、

def hogehoge
    処理内容
rescue => e
    エラー内容をSentryというイベントログを管理できるソフトに送信
    raise
end

hogehogeメソッドの中にある処理内容でエラーが発生したら、例外を捕捉して、また例外を発生させているというところまでは理解できたのですが、腑に落ちていない感覚がありました😵

なんでまた例外をわざわざ発生させているのかという点が疑問でした、、

本書を読むことで、やっと腑に落ちました!

まずhogehogeメソッドの中にある処理内容でエラーを捕捉したら、hogehogeメソッドの後に続く処理が継続してしまいます。処理の継続はしたくないですが、エラーメッセージをSentryに情報は送りたいという要望があります。その要望を満たすために、raiseでわざわざ例外を発生させることで、hogehogeメソッドの後に続く処理が継続しないようにしているということでした。

ご参考までにSentryの詳細は以下にございます。
Sentryでイベントログ収集をしよう! - Vue.js編 -


bundle execコマンドの意味について知れたこと

実務でよくbundle exec rails routesbundle exec rails cなどのコマンドを使用しておりましたが、そもそもなんでbundle execを先頭につけなえればいかないのかが疑問でした😅
(ただのおまじないなのかと、、)

上記の疑問を解消するためにはまずBundlerというgemを理解する必要がありました。Bundlerはgemの依存関係やバージョンを管理してくれます。例えば、Aというgemを使用するためには、Bというgemをインストールしなければいけませんが、ユーザがわざわざBのgemもインストールしなくてもBundlerが空気を読んで、Bというgemをインストールしてくれます。

そして、Bundlerで管理されているgemのコマンドを使用したい場合にはbundle execを先頭につけなければいけません。私が毎回叩いていたrails routesrails cはrailsのgemに関するコマンドでしたため、それをBundler経由で使用するためにはbundle execをつけなければいけなかったということを知れたのは目からウロコでした😳


selfについて

selfがメソッドの前についていたら、クラスメソッドと思っていたのですが、そうではない場合もあることを知りました。

例えば、以下コードです。

class Test
    def self.hogehoge
        puts "hogehoge" 
    end

    def hoge
        self.huga
    end

    def huga
        puts "hugahuga"
    end

以下の通りに実際にコードを実行してみましたところ、def self.hogehogeTest.hogehogeでうまく呼び出せているので、クラスメソッドです。

irb(main):032:1* class Test
irb(main):033:2*     def self.hogehoge
irb(main):034:2*         puts "hogehoge"
irb(main):035:1*     end
irb(main):036:1*
irb(main):037:2*     def hoge
irb(main):038:2*         self.huga
irb(main):039:1*     end
irb(main):040:1*
irb(main):041:2*     def huga
irb(main):042:2*         puts "hugahuga"
irb(main):043:1*     end
irb(main):044:1* end
=> :huga
irb(main):045:0>
irb(main):046:0>
irb(main):047:0> Test.hogehoge
hogehoge
=> nil
irb(main):048:0>

一方、self.hugaもクラスメソッドと思いきやTest.hugaで実行してみたところ、エラーが出ました😱

irb(main):053:0> Test.huga
Traceback (most recent call last):
        5: from /Users/yokoyamagen/.rbenv/versions/3.0.0/bin/irb:23:in `<main>'
        4: from /Users/yokoyamagen/.rbenv/versions/3.0.0/bin/irb:23:in `load'
        3: from /Users/yokoyamagen/.rbenv/versions/3.0.0/lib/ruby/gems/3.0.0/gems/irb-1.3.0/exe/irb:11:in `<top (required)>'
        2: from (irb):49:in `<main>'
        1: from (irb):50:in `rescue in <main>'
NoMethodError (undefined method `huga' for Test:Class)
irb(main):054:0>

self.hugaはインスタンスメソッドなのかと思い、以下のコードを実行したところ、うまくメソッドを呼び出せました!

irb(main):054:0>
irb(main):055:0> test = Test.new
=> #<Test:0x00007fe2a8884ae0>
irb(main):056:0>
irb(main):057:0> test.huga
hugahuga
=> nil
irb(main):058:0>

どうして上記のようになるのかを調べるためにselfの中身を以下コードで確認してみます。

class Test
    puts "クラス構文直下のself: #{self}"
    def self.hogehoge
        puts "クラスメソッド直下のself: #{self}"
    end

    def hoge
        puts "インスタンスメソッド直下のself: #{self}"
    end
end

クラス構文直下とクラスメソッド直下のselfはクラス名であるTestを指しておりますが、インスタンスメソッド直下のselfは#Test:0x00007fe2a80244b8というインスタンを指していることが分かりました。

irb(main):061:0>
irb(main):062:1* class Test
irb(main):063:1*     puts "クラス構文直下のself: #{self}"
irb(main):064:2*     def self.hogehoge
irb(main):065:2*         puts "クラスメソッド直下のself: #{self}"
irb(main):066:1*     end
irb(main):067:1*
irb(main):068:2*     def hoge
irb(main):069:2*         puts "インスタンスメソッド直下のself: #{self}"
irb(main):070:1*     end
irb(main):071:0> end
クラス構文直下のself: Test
=> :hoge
irb(main):072:0>
irb(main):073:0> Test.hogehoge
クラスメソッド直下のself: Test
=> nil
irb(main):074:0>
irb(main):075:0> test = Test.new
=> #<Test:0x00007fe2a80244b8>
irb(main):076:0>
irb(main):077:0> test.hoge
インスタンスメソッド直下のself: #<Test:0x00007fe2a80244b8>
=> nil
irb(main):078:0>

selfは定義する場所によって、クラスであったり、インスタンスであることを学びました☺️
インスタンスメソッドの前についているselfは暗黙的に定義されているため、明示的に書かなくてもよいです。

selfがメソッド名の前についていたら、クラスメソッドだけでなく、インスタンスメソッドの可能性もあるのだなと学びました!
selfが定義されているのがインスタンスメソッドの中なのか、クラス構文直下なのか、定義されている場所も把握する必要があると思いました。

難しかったこと

「クラスの作成を理解する」という箇所のcase文と===の関係がうまく理解できなかったため、また時間をおいて読み直した時には理解できるようになっていたいです😅

感想

一通り本書を読んでみて、以前よりも公式マニュアルを読むことが苦痛に感じることがなくなったのではないかと思いました🤩
今まで用語の理解をしっかりと行っていなかったのを今回の学習を通して、理解できるようになったことが大きいのではと思っております。

また、Railsを読む際にもRubyの名前空間や例外処理を理解したことによって、よりコードの内容が頭の中に入るようになったと感じております。

時間をおいて何度でも読み直したい一冊だと感じました!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0