クロージャについて勉強した

はじめに

クロージャについて友人と勉強会を行ったので、学んだことや理解したことをまとめておきたいと思います。

対象読者

  • クロージャについて雰囲気だけでも知っておきたい人
  • 初心者がどのようにクロージャを学んでいるのか気になる人

クロージャについてしっかり説明してる記事ではないので、その点はご了承下さい。

また、説明において間違ってる箇所がありましたら、教えて頂けると幸いです。

もくじ

クロージャよくわからない

クロージャについてMDNの説明をみてみます。

クロージャは、組み合わされた(囲まれた)関数と、その周囲の状態(レキシカル環境)への参照の組み合わせです。

クロージャ - JavaScript | MDN

組み合わされた(囲まれた)関数?

その周囲の状態(レキシカル環境)?

???

よくわからないですね。。。

一つずつ理解していくことにしました。

組み合わされた(囲まれた)関数って何?

よくわからないので、MDNでコード例をみてみました。

function init() {
  var name = 'Mozilla'; // name は、init が作成するローカル変数

  function displayName() { // displayName() は内部に閉じた関数
    alert(name); // 親関数で宣言された変数を使用
  }
  displayName();
}
init();

クロージャ - JavaScript | MDN からコード例を引用)

上の例でいうと、init関数のなかに、displayName関数が定義されています。(※ JavaScriptは関数の中に関数を定義できます。)

displayName関数はinit関数に囲まれていますね。

つまり、関数の中に関数がある状態のことを「組み合わされた(囲まれた)関数」と表現しているようです。

レキシカル環境って何?

これもよくわからないので、検索して出てきたWikipediaの説明をみることにしました。

静的スコープ(せいてきスコープ、英: static scope)とは、プログラミング言語におけるスコープの一種。字句のみから決定できるため、字句スコープまたはレキシカルスコープ (lexical scope) ともいう。

静的スコープ - Wikipedia

Wikipediaによると、レキシカルスコープは静的スコープとも言うようです。

静的スコープについてコード例を用いて理解することにしました。

静的スコープの例

下記は静的スコープを説明したコード例です。

// 静的スコープの例
const x = 1;
const hoge = () => {
  console.log(x);
};

const piyo = () => {
  const x = 3;
  hoge();
};

piyo(); // xの値は1または3どちらが出力される?

上記のコードの1行目では変数xがグローバル変数として定義されています。

piyo関数の中で変数xがローカル変数として定義されていて、処理の中でhoge関数が呼び出されています。

ここでpiyo関数を実行すると、変数xの値は1または3どちらが出力されるでしょうか?

const x = 1;
const hoge = () => {
  console.log(x);
};

const piyo = () => {
  const x = 3;
  hoge();
};

piyo(); // 1

実行すると、xの値は1が出力されています。つまり、グローバル変数xの値が参照されているということになります。

よって、hoge関数が実行された環境ではなく、定義された環境で、変数xの値が決まっていることがわかります。

静的スコープとは、定義された時点でスコープが決まるという概念ぽいです。

ちなみに、変数xへの参照はスコープチェーンによって決まっています。

スコープチェーンについて → https://jsprimer.net/basic/function-scope/#scope-chain

逆に、動的スコープという概念もあるそうです。動的スコープなら、hoge関数が実行された環境で変数xの値が決まります。

// JavaScriptが動的スコープを採用してる場合こうなる(擬似的なコード)
const x = 1;
const hoge = () => {
  console.log(x);
};

const piyo = () => {
  const x = 3;
  hoge();
};

piyo(); // 3

動的スコープが使用されてるプログラミング言語もあるらしいのですが、JavaScriptは静的スコープが使用されてるようです。

まとめると、レキシカルスコープとは、静的スコープの別名で、定義時にスコープが決定するものという理解でよさそうです。

で、クロージャってなんなの?

言葉の説明だけではイメージしずらいということで、コード例を用いて理解していくことにしました。

下記のコードは、クロージャが使われている例です。

const counter = () => {
  let count = 0;
  const innerCounter = () => {
    count += 1;
    return count;
  };
  return innerCounter;
};

const myCounter = counter();
console.log(myCounter()); // 1
console.log(myCounter()); // 2

counter関数の中にinnerCounter関数があります。

counter関数は戻り値として内部のinnerCount関数自体を返します。

innerCount関数内の処理としては、呼び出されるたびに、変数countの値が+1されるというものです。

よくみると、innerCounter関数内で外側の関数への環境にある変数countを参照しています。

この「innerCounter関数からcounter関数内の環境への参照の組み合わせのこと」(今回で言うと、innerCounter関数と変数countの関係のこと)をクロージャと呼んでいます。

ここで再度MDNのクロージャの定義を確認してみます。

クロージャは、組み合わされた(囲まれた)関数と、その周囲の状態(レキシカル環境)への参照の組み合わせです。

今までの理解を踏まえて、上記の説明について自分はこう解釈しました。

クロージャとは、「内部にある関数からその外側の関数の環境への参照の組み合わせのこと」である。

クロージャの特徴

クロージャのイメージが少し掴めたところで、今度はクロージャの特徴をみてみることにしました。

特徴としては大きく2つありました。

  1. 参照される外側の環境にある変数はプライベートな変数として扱うことができる
  2. 参照される外側の環境にある変数の値は、参照され続ける限り値が保持される

先ほどのコード例でみていきたいと思います。

1. 参照される外側の環境にある変数はプライベートな変数として扱うことができる

1つ目の特徴についてです。

const counter = () => {
  let count = 0;
  const innerCounter = () => {
    count += 1;
    return count;
  };
  return innerCounter;
};

const myCounter = counter();
console.log(myCounter()); // 1
console.log(myCounter()); // 2

// 外部から変数countの値は変更できない
// JavaScriptは静的スコープなので、innerCounter関数が参照する変数countは定義時にcounter関数の環境にある変数countであると決まる
const count = 100;
console.log(myCounter()); // 3

この例でいうと変数countをプライベートな変数として扱うことができるということです。

というのも、変数countの値は外部から変更することはできなくなっています。

これは静的コープの理解にもつながりますね。(定義時に参照先が決まる)

変数countの値を変更したい場合は、innerCounter関数を実行するしかないのです。ゆえに、グローバル変数を使用しない安全なコードにできるという利点があります。

2. 参照される外側の環境にある変数の値は、参照され続ける限り値が保持される

続いて2つ目の特徴についてです。

同じく先程のコードでみていきたいと思います。

const counter = () => {
  let count = 0;
  const innerCounter = () => {
    count += 1;
    return count;
  };
  return innerCounter;
};

const myCounter = counter();
console.log(myCounter()); // 1
console.log(myCounter()); // 2

// 参照先を変えると変数countの値は別で保持される
const otherCounter = counter();
console.log(otherCounter()); // 1
console.log(otherCounter()); // 2
console.log(otherCounter()); // 3
console.log(otherCounter()); // 4

console.log(myCounter()); // 3

上記のコードの変数myCounterには、counter関数の実行内容つまり、innerCounter関数自体が入っています。

変数countはinnerCounter関数内から参照されています。つまり、変数myCounterによってinnerCounter関数が参照され続ける限り、変数countの値も参照され続けることになります。

そのため、myCounter()を実行する度に、値が1ずつ増えていくことになるということです。

また、参照先を変えると変数otherCounterが持っている変数countの値は、変数myCounterがもっている変数countの値とは別で保持されます。

以上より、クロージャには大きく2つの特徴があることが分かって頂けたと思います。

続いてはクロージャが使われてるコード例をいくつか紹介したいと思います。

ちょっと補足

クロージャのコード例は即時実行関数を使って書かれていることが多いです。

先ほどのコード例を即時実行関数を用いて書くと、以下のようになります。

const counter = (() => {
  let count = 0;
  const innerCounter = () => {
    count += 1;
    return count;
  };
  return innerCounter;
})();

const myCounter = counter;
console.log(myCounter()); // 1
console.log(myCounter()); // 2

クロージャのコード例をみると度々使われているので、少し補足で紹介しておきました。

クロージャを使った他の例

クロージャを使った他の例を簡単にですが紹介しようと思います。

メソッドを使ってオブジェクト指向っぽい使い方ができる

下記のコードではreturn以下のincrementメソッド内とdecrementメソッド内で変数countが参照されています。

つまり、変数countとincrement, decrementメソッドの関係もクロージャと言えます。

こののような実装にすることで、クラスを使わずに関数が状態をもつように振る舞わせることができます。(オブジェクト指向っぽい使い方が可能になる)

const counter = () => {
  let count = 0;
  return {
    increment: () => {
      count += 1;
      return count;
    },

    decrement: () => {
      count -= 1;
      return count;
    },
  };
};

// オブジェクト指向っぽく使用できる
// 状態をもつ & 外部から変数が変更されない

const myCounter = counter();
console.log(myCounter.increment()); // 1
console.log(myCounter.increment()); // 2
console.log(myCounter.increment()); // 3
console.log(myCounter.decrement()); // 2

const otherCounter = counter();
console.log(otherCounter.decrement()); // -1
console.log(otherCounter.decrement()); // -2

関数とスコープ · JavaScript Primer #jsprimer からコード例を引用)

カリー化もクロージャが使われてる

JavaScriptにはカリー化というテクニックがあります。

下記のコードはカリー化の例です。

innerFunc関数内で変数xが参照されていますが、このinnerFunc関数と変数xの関係もクロージャの関係であると言えます。

const addFunc = (x) => {
  const innerFunc = (y) => {
    return x + y;
  };
  return innerFunc;
};

const addFive = addFunc(5); // 部分適用
const addSeven = addFunc(7); // 部分適用
console.log(addFive(10)); // 15
console.log(addSeven(10)); //  17

クロージャ - JavaScript | MDN からコード例を引用)

Rubyにもクロージャがある?

Rubyでもクロージャが使われてる例を学んだので紹介します。

Procオブジェクト作成する際に、ブロック内から変数countが参照されています。

このProcオブジェクトと変数countの関係がクロージャとなっています。

def counter
  count = 0
  Proc.new { count += 1 }
end

my_counter = counter # 変数my_counterでcounterメソッドを参照しておく
# 変数countの値を保持できる
puts my_counter.call #=> 1
puts my_counter.call #=> 2
puts my_counter.call #=> 3

Rubyにおけるクロージャについては、『プロを目指す人のためのRuby入門』(通称 チェリー本)でも紹介されていました。(p. 433 10.5.3 「Proc オブジェクトとクロージャ」)

気になる方はぜひ確認してみて下さい🍒

参考: RubyJavaScriptのスコープの違い

少し話はそれてしまいますが、RubyJavaScriptのスコープの違いについても勉強になったので紹介します。

Rubyではトップレベルの変数に対してメソッド内から変数の参照はできないのに対して、JavaScriptはそれが可能であるという言語の違いがあります。

当たり前かもしれないですが、自分はあまり意識したことがなかったのでハッとしました。

# Ruby
count = 0
def counter
  puts count
end

counter #=> undefined local variable or method `count' for main:Object (NameError)
# エラーになる
// JavaScript
let count = 0;
const counter = () => {
  console.log(count);
};

counter(); // 0
// 参照できる

クロージャまとめ

クロージャとは、「内部にある関数からその外側の関数の環境への参照の組み合わせのこと」

また、クロージャの特徴として以下の2つがあげられる。

  1. 参照される外側の環境にある変数はプライベートな変数として扱うことができる
  2. 参照される外側の環境にある変数の値は、参照され続ける限り値が保持される

わかってないこと

JavaScriptの関数は全てクロージャである。という記述をよく見るのですが、あまりピンときていないです・・

また、@haruguchi さんにクロージャを使ったキャッシュとメモ化の利用方法を教えてもらったのですが、理解できていないので書いていません。理解出来たら書こうと思います。

さいごに

きちんと理解できていない箇所もありますが、わかっている範囲でクロージャについてまとめました。

間違って説明している箇所などありましたら、教えて頂けると幸いです。

JavaScriptについてわからないことが増えたので、引き続き学習していきたいと思います。

参考

Ruby SilverとGoldに合格した

はじめに

Ruby 3に対応したRuby技術者認定試験に合格しました。

Ruby Association Certified Ruby Programmer Silver version 3

Ruby Association Certified Ruby Programmer Gold version 3

www.ruby.or.jp

Ruby Silverの方は94点、Goldの方は86点でした。

目次

Ruby力について

読んだことあるRubyの書籍は、ゼロからわかる Ruby 超入門プロを目指す人のためのRuby入門(通称:チェリー本)です。

実務経験は半年ほどです。

受験経緯

資格試験がRuby 3にアップデートされたためです。いいタイミングで一回落ちても再度受験可能キャンペーンがあったので、落ちてもOK精神で受験を決めました。

【終了】Ruby技術者認定試験再受験無料キャンペーン(2022年10月3日開始)

勉強時間

Silver

12/14 ~ 12/28(12/28受験)

20 ~ 25hほど

Gold

12/29 ~ 1/10(1/10受験)

25hほど

※ Silverの方は昔ちょこちょこRExを解いたりしたこともあったりなど、正確な時間ではないです

やったこと

SilverもGoldもどちらも、

  1. RExで9割〜10割安定するまでやる
  2. 模擬問題集・合格教本(最後の方についてる問題集2つ)を満点取れるまでやる
  3. 直前に受験体験記を見る

という方針で学習しました

具体的にやったこと

Silver

  • REx 12回

  • 模擬問題集 4回

  • 合格教本(最後の方についてる問題集2つ) 3回

Gold

  • REx 8回

  • 模擬問題集 5回

  • 合格教本(最後の方についてる問題集2つ) 3回

受験して思ったこと

参考にさせてもらった記事

思ったこと

Rubyについて知らないことがたくさんあることがわかったのと、会社の人が喜んでくれたのでそれだけでも勉強してよかったと思いました。

FjordBootCampというプログラミングスクール内で実施されていた、ゼロからわかる Ruby 超入門プロを目指す人のためのRuby入門(通称:チェリー本)の輪読会で学んだ知識がとても役に立ちました!

maeda-seina.hatenablog.com

おわりに

Rubyについてわからないことが増えたので、引き続き学習していきたいと思います

Discordrb + Heroku Schedulerでのやらかしについて

はじめに

フィヨルドブートキャンプで学習しています@Maedaといいます。 現在自作サービスを作るプラクティスでDiscord Botの作成に取り組んでいます。

Discordrb + Heroku Schedulerを使用した際につまづいたことについて話していきたいと思います。

目次

現在作成しているもの

Discordサーバー内のテキストチャンネルからランダムに一つ選び毎朝アナウンスしてくれる、テキストチャンネル紹介botを作成しております。

ruby-jpではrubotyというSlack botが毎朝9時にサーバー内のチャンネルをランダムで一つ紹介してくれています。このDiscord版(フィヨルドブートキャンプのDiscordサーバー内で使用)を作成しています。

まだ作成は終わっていませんが、こんな風にDiscord botがチャンネル紹介をしてくれるイメージです↓

botが毎日決まった時間にチャンネル紹介するようにしたいな〜と思ったのが、Heroku Schedulerを導入した経緯になります。

はまったところについて

では早速、自分がはまったことについてです。

Heroku Schedulerを導入する上で、まず1時間に一回定期実行してくれるのかをテスト検証してみようと思い、毎時間30分(1:30→2:30→3:30...)になったらチャンネル紹介するコマンドを実行するというjobをHeroku Schedulerに登録しました。

その結果、3時間に1回しかbotがチャンネル紹介してくれないという問題が発生しました...

(下の画像のような感じで、3時間に1回しかbotがチャンネル紹介してくれない...)

なんでだろう...という状態だったので、一つ一つ原因を調査してみることにしました。

調査

調査をフィヨルドブートキャンプのメンターの方と一緒に行って頂きました。

まずは、きちんとデプロイやHeroku Schedulerの設定がうまくできているかを確認しました。

→ここはHerokuのドキュメント通りに行ったため、問題なさそうということになりました。

次に、設定したjobがきちんと実行されているかどうかを確認をするため、「ログを集める・読む」ということを行いました。

ログの情報から、実行されたプロセスがずっと残り続けている。ということがわかり、ここが怪しいのではないか?ということに。(本来であれば、Process exited with status 0State changed from up to completeというような感じで、プロセス自体が完了になっているはず!)

(実際のログ↓)

Mar 16 01:30:24 rocky-temple-69583 heroku/scheduler.6680 Starting process with command `bundle exec ruby bin/bot_run.rb`
Mar 16 01:30:24 rocky-temple-69583 heroku/scheduler.6680 State changed from starting to up
Mar 16 02:32:30 rocky-temple-69583 heroku/scheduler.6680 Cycling
Mar 16 02:32:30 rocky-temple-69583 heroku/scheduler.6680 State changed from up to complete
Mar 16 02:32:31 rocky-temple-69583 heroku/scheduler.6680 Stopping all processes with SIGTERM
Mar 16 02:32:31 rocky-temple-69583 heroku/scheduler.6680 Process exited with status 143
Mar 16 04:30:09 rocky-temple-69583 heroku/scheduler.1568 Starting process with command `bundle exec ruby bin/bot_run.rb`
Mar 16 04:30:10 rocky-temple-69583 heroku/scheduler.1568 State changed from starting to up
Mar 16 05:31:08 rocky-temple-69583 heroku/scheduler.1568 Cycling
Mar 16 05:31:08 rocky-temple-69583 heroku/scheduler.1568 State changed from up to complete
Mar 16 05:31:10 rocky-temple-69583 heroku/scheduler.1568 Stopping all processes with SIGTERM
Mar 16 05:31:10 rocky-temple-69583 heroku/scheduler.1568 Process exited with status 143
Mar 16 07:30:19 rocky-temple-69583 heroku/scheduler.6649 Starting process with command `bundle exec ruby bin/bot_run.rb`
Mar 16 07:30:19 rocky-temple-69583 heroku/scheduler.6649 State changed from starting to up
Mar 16 08:31:30 rocky-temple-69583 heroku/scheduler.6649 Cycling
Mar 16 08:31:30 rocky-temple-69583 heroku/scheduler.6649 State changed from up to complete
Mar 16 08:31:31 rocky-temple-69583 heroku/scheduler.6649 Stopping all processes with SIGTERM
Mar 16 08:31:31 rocky-temple-69583 heroku/scheduler.6649 Process exited with status 143

(実際の画像↓)

そもそも、このサービスのやりたいこととしては「Discord Botが毎日1回サーバー内のテキストチャンネルをランダムに一つ紹介する。」それだけであるので、 本来であればプロセスが生き続けている事自体がおかしいことに気づきました。

そこで初めて、不必要にbotを稼働させてしまっていることに気づきました。。。(ログを見るまでは気づいてませんでした...)

コードを見てみると、自分が行いたいことは 「botがチャンネルにメッセージを送るようにする」という事であり、それはDiscordrb::API::Channel.create_message(...)で実現できているのにも関わらず、「botを継続的に稼働させるようにする」という行う必要のないDiscordrb::Bot.new(...).runまで行うようにコードを書いてしまっている事がわかりました。


参考

  • Discordrb::API::Channel.create_messageについて

https://drb.shardlab.dev/v3.4.0/Discordrb/API/Channel.html#create_message-class_method

  • Discordrb::Bot.new(...).runについて

https://drb.shardlab.dev/v3.4.0/Discordrb/Bot.html#run-instance_method


「不必要にbotを稼働させてしまっていた」ここが今回の一番のやらかしポイントでした。

この部分を修正しデプロイし直した結果、きちんとHeroku Schedulerが作動し、1時間毎にチャンネル紹介をしてくれるようになりました。

修正したPRです

github.com

なぜチャンネル紹介が3時間おきに行われたのか?について

Heroku Schedulerの話に戻りますが、1時間おきにHeroku Schedulerが実行されるようjobを設定しているのにも関わらず、3時間おきに実行されてしまうという問題がありました。

この件について調べてみたところ、Heroku Schedulerのログの中にあるサイクルがあることがわかりました。

(実際のログ↓)

# ---ここから
Mar 16 01:30:24 rocky-temple-69583 heroku/scheduler.6680 Starting process with command `bundle exec ruby bin/bot_run.rb`
Mar 16 01:30:24 rocky-temple-69583 heroku/scheduler.6680 State changed from starting to up
Mar 16 02:32:30 rocky-temple-69583 heroku/scheduler.6680 Cycling
Mar 16 02:32:30 rocky-temple-69583 heroku/scheduler.6680 State changed from up to complete
Mar 16 02:32:31 rocky-temple-69583 heroku/scheduler.6680 Stopping all processes with SIGTERM
Mar 16 02:32:31 rocky-temple-69583 heroku/scheduler.6680 Process exited with status 143
# ---ここまで

# ---ここから
Mar 16 04:30:09 rocky-temple-69583 heroku/scheduler.1568 Starting process with command `bundle exec ruby bin/bot_run.rb`
Mar 16 04:30:10 rocky-temple-69583 heroku/scheduler.1568 State changed from starting to up
Mar 16 05:31:08 rocky-temple-69583 heroku/scheduler.1568 Cycling
Mar 16 05:31:08 rocky-temple-69583 heroku/scheduler.1568 State changed from up to complete
Mar 16 05:31:10 rocky-temple-69583 heroku/scheduler.1568 Stopping all processes with SIGTERM
Mar 16 05:31:10 rocky-temple-69583 heroku/scheduler.1568 Process exited with status 143
# ---ここまで

# ---ここから
Mar 16 07:30:19 rocky-temple-69583 heroku/scheduler.6649 Starting process with command `bundle exec ruby bin/bot_run.rb`
Mar 16 07:30:19 rocky-temple-69583 heroku/scheduler.6649 State changed from starting to up
Mar 16 08:31:30 rocky-temple-69583 heroku/scheduler.6649 Cycling
Mar 16 08:31:30 rocky-temple-69583 heroku/scheduler.6649 State changed from up to complete
Mar 16 08:31:31 rocky-temple-69583 heroku/scheduler.6649 Stopping all processes with SIGTERM
Mar 16 08:31:31 rocky-temple-69583 heroku/scheduler.6649 Process exited with status 143
# ---ここまで
  1. Heroku Schedulerが起動し、bundle exec ruby bin/bot_run.rbが実行された結果ファイル内に記載されている、Discordrb::API::Channel.create_messageが実行されてチャンネル紹介が行われ、Discordrb::Bot.new(...).runが実行されてbotの稼働が始まる。

  2. 1時間後、Heroku Schedulerが起動するも、Cycling(再起動が実行)が行われ、まだ残っているプロセス(Discordrb::Bot.new(...).run)を強制終了させる。(jobに設定してあるbundle exec ruby bin/bot_run.rbは実行されていない)

  3. 1時間後、実行されるはずのHeroku Schedulerが起動されない。→1に戻る。

→ この1~3のサイクルが繰り返されて、3時間毎にチャンネル紹介がされていたということがわかりました。


色々調査しましたが結局のところ、

  • 2.で、Heroku Schedulerに設定したコマンドが実行されずに、プロセスを殺しただけで終了してしまっていること。
  • 2.で残っているプロセスを殺して終了した後、1時間後に実行されるはずのHeroku Schedulerが全く実行されていないこと。(その1時間後に再び定期実行されるようになる)

この2点に関してはなぜなのかわかりませんでした...

(わかる方がいらっしゃれば、コメントしてくださると幸いです。)


追記(3/30)

jnchitoさんからコメントいただきましたので、追記させて頂きます。

ここは僕もよくわからないのですが、Schedulerのドキュメントの「Long-running jobs」を読むと、そもそも「スケジューリング間隔をオーバーするような長時間のタスクはSchedulerを使うな」的なことが書いてあるので、あまり深追いしなくても良さそうな気がします。想定外の使い方をしてしまったので想定外の動きになった、ぐらいな結論でいいかもしれません。数秒〜数分で終わる適切なタスクを設定する上では、こういった問題は起きないはずなので。

https://devcenter.heroku.com/articles/scheduler#long-running-jobs

Heroku側も想定していない使い方をしてしまっていたので、どれだけ調べても推測でしかわからなそうということです。。。

そもそもの使い方がイレギュラーすぎると、原因も追いにくいということが分かりました😓

今回のまとめ

botを稼働させるという必要のないことをしてしまい、Heroku Schedulerが1時間後に次のコマンドを実行するときに前のプロセスが残り続けている。という問題が起きた結果、今回のような3時間に1回しか実行されないという問題に繋がってしまった。というのが今回の一連の流れです。

自分のやりたいこととしては、サーバー内のチャンネル情報を取得し、その情報をフォーマットし、その結果をbotに出力させる。ということなので、「スクリプトを実行する」ことで事足りるにも関わらず、使わなくてもいい機能であるDiscordrb::Bot.new(...).runを行ってしまっていた。ということが一番のやらかしポイントでした。 (Discordrb::Bot.new(...).runを行う必要があるのは、そのサーバー内にbotを常駐させて何かコマンドに対して反応させる必要がある時のような場合に行う)

学んだこと

  • Discord bot動作させる上で、 Discordrb::Bot.new(...).runを行うことが必要条件ではないことを学びました。(Discordrb::Bot.new(...).runbot稼働させる上で最低限必要なもの。)

  • Herokuのログを見るには、Papertrailというアドオンを入れておくと良い。

→ターミナルからもログはみれるが、Papertrailは検索機能がありとても使いやすかった。

→設定からTime zoneを日本時間に変更できる。(デフォルトではUTCで設定されているので、少し見づらい。)

  • 新しい技術(今回でいうとDiscordrbライブラリとHeroku)を使うときは、きちんとドキュメントを読むことが大事であると実感しました。きちんと理解しないまま使用すると、こんなこと間違えるわけない!!!という間違いを平気でしてしまうことがわかりました。

おわりに

最後まで読んでいただき、ありがとうございます。

この問題で1週間くらい悩まされたので、原因がわかったときは本当にスッキリしました! 一緒に調査して頂いた、フィヨルドブートキャンプのメンターの@cafedomancerさんありがとうございました!

また、今回このようにブログ記事にしたのも、 これまたフィヨルドブートキャンプのメンターである、伊藤淳一 (id:JunichiIto) さんにフィヨルドブートキャンプのDiscordサーバー内で自分(@Maeda)の調査方法(問題に対して「仮説」→「検証」を全然行えていなかった)が良くないとご指摘を受けたところから始まりました。(まだよくわかってない箇所がいくつかありますが...) 記事としてまとめるきっかけを頂き本当に感謝しております。

自分のようなことではまらない人が出ないことを祈っています!

輪読会のすすめ

はじめに

この記事はフィヨルドブートキャンプ Advent Calendar 2021 Part 1 24日目の記事です。

フィヨルドブートキャンプ Advent Calendar 2021 Part 2もあります。

本日Part2の方の記事はSakiさんの記事になります!楽しみです!

昨日はあじたまさんの記事でした。

azitama.com

目次

簡単な自己紹介

フィヨルドブートキャンプ32期生のMaedaと申します。

Webエンジニアを目指してフィヨルドブートキャンプで学習中です。

なぜこの記事を書こうと思ったか

この約4ヶ月間輪読会に参加してみて、輪読会良いな〜という思いでいっぱいなので、その気持ちを書きたい!と思ったためです。

この記事を読んで、輪読会に参加してみたいな。輪読会いいな。と思っていただければ嬉しいです。

では早速、輪読会で個人的に良かったな〜と思うポイントをつらつらと書いていこうと思います。

注意

この記事はフィヨルドブートキャンプ生向けの内容になっている箇所が少なからずあります。

その点はご了承ください。

輪読会とは?

フィヨルドブートキャンプにいると輪読会という言葉があまりにも当たり前に使われています。ですが輪読会って何?っていう人もいらっしゃると思いますので簡単に説明しておきたいと思います。

数人が一つの本を順番に読んで解釈をし、問題点について論じ合ったりすること。 (デジタル大辞泉「輪読」の解説)

フィヨルドブートキャンプで行われている輪読会は、 司会・ドライバー・読む順番を決めて、モブプロ形式で一つの本を順番に読んでいき、わからないところや疑問に思ったことがあればその場で質問し、最後にHackMDに気づきや学びを書き、一人づつ発表する。という流れで行われています。

これだけの説明ではわかりにくいと思うので、より具体的に知りたい方は下の記事を参照してください。輪読会がどのようなものかイメージつくと思います!

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

チェリー本輪読会を完走した感想 - Leap of faITh

チェリー本輪読会を完走しました - やなぎにっき

shirotamaki.hatenablog.com

isshi-hasegawa.hatenablog.com

yana-g.hatenablog.com

参加したいと思ったきっかけ

輪読会のワイワイとした熱気が伝わってきて楽しそうだな〜と思った。

輪読会きっかけでもくもく会が始まったりなど、外から見ていると、とても楽しそうで、個人で細々と学習していたこともあり、かなり羨ましく思っていました。

輪読会にラジオ参加した時に、めっちゃ勉強になる!すごい!!!と感銘を受けた。

雰囲気でコードを読んでしまっていた自分からして、論理的にコードを読み下していた前チェリー本輪読会の皆さんの凄さは今でも覚えています!(現在開催されているチェリー本輪読会は2代目です。) 皆さんみたいにRubyが読めるようになりたいなと思い、輪読会に参加したいなと思いました。

本読むのが苦手で、輪読会の力を借りたいと思った。

チェリー本輪読会を主催してくださっているParuさんの記事に書いてあるように、まさに自分もなかなか一人では本を読み進めるのしんどいな〜と悩んでいました。

本が読めない人だったことに今頃気づいた私が輪読会に救われた話 - Every day is a new day.

paru871.hatenablog.com

参加して良かったこと

Rubyについてとにかく勉強になる。

+ってInteger#+メソッドだったんだ。とか、if文って実は式だったんだ。とか、イミュータブルなクラスには破壊的メソッドがないんだ。とか、メソッド呼び出しには必ずレシーバが必要で、なくても動いているのは省略されているだけだったんだ。などなど...

ここには書ききれないほどたくさん学びがありました。 どれも個人での学習では気づけなかったことばかりです!

コードの読み方を教えてもらった。

今まではコードを雰囲気で読んでいただけだった。ということに気付かされました。 教えてもらったという言い方は語弊があるかもしれませんが、参加されている皆さんのコードの読み方を見たり、聞いたりするだけでかなり勉強になりました。 今までRuby難しいなと思っていたのですが、それはただコードを読むということができていなかっただけだったのかもしれないな。と今では思っています。 自分の学習のステージが上がったような気がしています!

参加してる人と仲良くなれた。

毎日参加していることもあり、徐々に参加メンバーと仲良くなっていきます。 くだらないことを話したり、日報で励ましあったり、詰まっているプラクティスのことを質問したりなどなど、良い関係を築けているな〜ありがたいな〜と日々感謝しています。

輪読会でたら元気になるということが多々ある。

くっっっ...今日はなんか元気出ないな。という日でも輪読会出てみると、皆さんからエネルギーをもらって切り替えて学習できたりすることが多いです!

コミュニケーションを取れる場所ができた。

一人ではどうしても孤独な学習となりがちです。 少しの悩みでも相談できる人がいるだけで心がかなり楽になります。 輪読会参加が学習を続けられている要因の一つになっているなと感じています。

公式リファレンスを読む癖がついた

わからないことが出てきたら、まず公式リファレンスを参照するようになりました。これも輪読会のおかげで身についたことだと思います。

卒業生の方や現役エンジニアの方が参加してくれる

受講生同士で進めているため、全くわからない。という場面がよく出てきます。そんな時は卒業生の方や現役エンジニアの方が教えてくれたり、一緒に考えたりしてくれるのでとてもありがたいです。

本を細かく丁寧に読むという楽しさを教えてもらった。

チェリー本をかなり細かく丁寧に読み進めています。確かに時間がかかりますが、その分めちゃくちゃ深く学べて学びが多いです。こんなことまで書いてあるのか。といつもびっくりしています。 一人で読んでたら絶対にできないことだと思います。

コミュニティに慣れるということにつながる

質問タイムなどのコミュニティに参加するハードルが下がったように思います。 輪読会参加が、コミュニティ慣れにつながっているのかもしれないと感じてます。

参加するか迷う理由

勉強は個人でするものだ。

自分のペースで学習したい。という人には向いてないかもしれません。ただ、学習はめちゃくちゃ長いので、個人で学習していると辛くなってしまう。という人なんかは、みんなでワイワイやって進んでいくのがオススメなんじゃないか。と思っています。(自分がまさにそうです。)

読み終わるまで期間が長すぎる

早く終わらせてどんどん学習したいという人には向いていないかもしれません。逆に、少しずつ深く学びたいという人にはとっておきの学習機会だと思います。

よそもの扱いされたら嫌だな。

これは真逆です。参加してくれるだけで、みんなめっちゃ喜びます。

参加していて面白いと思ったこと

たまに特殊なイベントが発生する(開催してくれる人に感謝。)

輪読会のメンバーでモブプロやったり、難しかった単元や箇所の復習会をやったりなど。

最初は気づかなかった参加している人のいいところが見えてくる。

質問するのがうまい人、気配りがすごいできる人、説明がとにかくうまい人、場を和ませることができる人、指摘をするのが的確で早い人、調べるのが早い人、進行役がとても上手な人、まとめるのが上手い人、などなど。

チェリー本輪読会を気になっている方へ

開催日時

平日の18:00~19:00の1時間

現在やっているところ

第7章のクラスの章の途中です。

チェリー本輪読会特有の特徴

  • 優しい人が多い(主観)

  • 始まる前の10分間で悩み相談できる。

  • 最後全員一人一人が発表する時間がある。

チェリー本輪読会の具体的な流れ

18:00〜 プラクティスで詰まっているところなど、悩み相談したい人がいたら相談する時間になっている。その後、司会(進行役)とドライバー(画面共有してコードを打つ人)と読む順番を決める。(今は始まる前に事前に決まっている。)

18:10〜 本を読む人が、音読して読み進めていく。コードも読み下す。疑問点や気づいたことがあったらその場で質問する。

18:40〜 今日の学びと気づきをHackMDに書き込む。(学んだことを言語化する時間がある。)

18:45〜 学んだことを一人ずつ発表する。

19:00〜 解散

途中から参加するのなんだかな...という方へ

どしどしラジオ参加でも遊びに来てください。 来てくれたら輪読会メンバーみんな喜びます。 特に主催のParuさんが喜びます。

しかし、最初から参加して学習したいという気持ちはすごくわかります。自分もそうでした。

丁度、フィヨルドブートキャンプの卒業生であるふーがさんが主催される「りんどく.rb」でチェリー本の輪読会が1月頃から始まるそうです。(しかも第二版!!)

そしてこちらはフィヨルドブートキャンプ生じゃなくても参加できるそうです!

詳しくは、ふーがさんの記事に書かれているので気になる方は読んでみてください!

Rubyの技術書を輪読する”りんどく.rb”を立ち上げます - No day younger than today

fuga-ch85.hatenablog.com

また、🎍新春 輪読会EXPO🎍というイベントがフィヨルドブートキャンプ生向けにはなりますが、開催されます。 数々の輪読会を主催されてきたトミー (id:eatplaynap329)さんが主催されます。 現在フィヨルドブートキャンプで開かれている各輪読会の紹介などがあるそうなので気になる方は参加してみてください!

参加する勇気がなかなかでないという方へ

フィヨルドブートキャンプ生の輪読会やコミュニティ参加までの苦悩などが書かれている記事があります。 めちゃくちゃいい記事なのでぜひ読んでみてください。

本が読めない人だったことに今頃気づいた私が輪読会に救われた話 - Every day is a new day.

私のコミュニティ参加のきっかけについて - いろはにほへと

paru871.hatenablog.com

napple29.hatenablog.com

おまけ

現在輪読会で通読しているプロを目指す人のためのRuby入門(通称チェリー本)の著者である伊藤淳一 (id:JunichiIto)さんは、フィヨルドブートキャンプのメンターなのですが、一度だけ伊藤さんがふらっと輪読会に遊びにきてくださったことがありました。 その時に、「なんか質問ある?」と聞いてくださったのですが、 突然のことすぎてみんなびっくりしすぎて誰も質問できなかったということがありました笑

次の日、次来てもらった時に質問を用意しておかないと!ってみんなで反省会をしました。

おわりに

最後まで読んでいただきありがとうございました!

初ブログを書いた感想は、ブログ書くのはかなり体力がいる!ということです。これを知れただけでも書いてよかったな〜と思いました。

フィヨルドブートキャンプ生の皆さんのブログの書き方を参考にして作成させてもらいました! ありがとうございました。

明日はフィヨルドブートキャンプ Advent Calendar 2021 Part1 Part2の最終日となります。

最終日は、@komagataさんと、mh@mobiler⚡️さんの記事です!楽しみです!😄