『現場Rails』の輪読会が終了しました〜

現場で使える Ruby on Rails 5速習実践ガイド | 大場寧子, 松本拓也, 櫻井達生, 小田井優, 大塚隆弘, 依光奏江, 銭神裕宜, 小芝美由紀 |本 | 通販 | Amazon

フィヨルドーブートキャンプ内のDiscordで現在輪読会がたくさん発足している。

その中でも平日の朝9:00から毎日行っていた『現場Rails』の輪読会が今日で全部読み終わり、無事に終幕。

『現場Rails』が本当に自分にとってよかったので、ここに本の感想を残してみる。

  1. 環境構築、railsのイニシエーション、ルーティング、コントローラーとモデルのgenerate、ビューの作成まで、手順通りに書かれていて、自分があたらしくサービスを立ち上げる時の参考になる
  2. バリデーションやDBの制約や国際化やその他、単に動くアプリではなく、現場では必要な機能についても実装していくところもよい
  3. Rspec、capybara、slim、rails-ujsなどのライブラリについても詳しく書かれている
  4. ひとつひとつのコードの説明が分かりやすいので、コードをおまじないではなく意味のわかるものとして理解できる

要点はこんな感じ。

ところで、フィヨルドブートキャンプの最終課題ではWebアプリを自作する。

(現在も鋭意製作中) github.com

1からアプリを作るので、そういえばこの本にいろいろ書いてあったな〜と思って、読み直しながら作っていたら、いつのまにか最初の方の章は全部なめるように読み直してしまった。そのくらい、実践的な内容。

後の方の章はデザインパターンっぽい話なので、自分で応用するのは難しそうだけど、最初の方は初学者にぜひおすすめな内容になっていると思う。

自分は『パーフェクトRails』や『独習Rails』など他の本は読んでないので比較できないけど、2周した『Railsチュートリアル』よりはやや平易でとっつきやすいように思う。

文句らしい文句はないのだけど、少し苦労しているのは、本でなくKindleで購入してしまったところ。Kindle版はワード検索ができず、すぐに目当ての場所を読み返すのが難しい。せっかく索引があるのに電子書ではあまりそれが生きない。これから購入するのであれば紙の本か、検索できるPDFもあるそうなのでそちらをお勧めします。

スクールの課題でおおいにハマってしまい、最終課題に取り組んでからかれこれ半年は経つのだけど、この本の輪読会は、まったく手が止まってシワシワのインスタントラーメンみたいになっていた自分にお湯を注いでくれた。いまでは、また食べられるようにまでなったので、本と輪読会メンバーには感謝しかないです。

コミュニティの大切さを痛感しつつ、本の著者、輪読会の開催者および、アドバイザー、モチベーターのフィヨルド生たちに 🙏

postgresql13から14に上げた時のエラー対処

brew install rbenvをおこなったら、ついでのようにpostgresまでアップグレードされたけど、こんなようなエラーが出た。

psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed: Connection refused
    Is the server running locally and accepting connections on that socket?

psqlで入ろうとするとこうなるので、いろいろしらべて次のことをした。

一度アンインストール

brew uninstall postgresql

で一度アンインストールしてから

brew install postgresql

13から14へ既存のデータベースをアップグレード

2022-02-02 12:51:23.304 JST [850] FATAL:  database files are incompatible with server
2022-02-02 12:51:23.304 JST [850] DETAIL:  The data directory was initialized by PostgreSQL version 13, which is not compatible with this version 14.1.

こんなようなエラーも出るので

brew postgresql-upgrade-database

をする。これは過去に自分がversion13でつくったやつを、手元で最新にインストールしているversion14でも開けるようにする処理。

pidというのを削除

$ postgres -D /usr/local/var/postgres
2022-02-02 13:16:11.685 JST [5122] FATAL:  lock file "postmaster.pid" already exists
2022-02-02 13:16:11.685 JST [5122] HINT:  Is another postmaster (PID 4726) running in data directory "/usr/local/var/postgres"?

探した記事の中にはpidというのを削除すれば良いという記事もあった。上記のコマンドも実行してpidを/usr/local/var/postgres/postmaster.pidと特定して、削除する。けれど、これが効果あったかは不明

psqlのコマンドに引数を渡さないとエラーになる。

psql

でDBに入ろうとすると「致命的なエラー""というDBがありません」と言われるので、-d postgresなどで適当なDB名を指定すると入れる。 psqlは引数なしで実行した場合、linuxのユーザー名のDB名を探してログインしようとするためらしい。 「致命的」は言い過ぎでは...? 🙃

余談、psqlのログの場所

locateとかもしばらく使ってなかったので忘れていた...

$ sudo locate postgres.log
/usr/local/var/log/postgres.log

macOSのアップデートとcommand line tools for xcodeの導入

macOSをMontereyにアップグレードしようとしたらストレージが足らないと怒られた。

なので、一時的にXcodeをアンインストールしてストレージを稼いで、あとでXcodeは再インストールしようと目論んだ。

無事OSをMontereyにアップグレード

ところが、ちょっと心配していたことが起きてしまう。Xcodeを再インストールしようとしたら容量が足りないらしい。

XcodeがないとHOMEBREWがなくなって、rubyrailsも開発環境が復帰できない....

そこで、過去に試して挫折していたcommand line tools for xcode(CLT)の存在を思い出す。

CLTを使えばXcode本体の容量の10分の1くらいで開発環境が整うらしい。Xcode本体はスマホアプリ開発などをしない限り全部は必要ないらしい。

以下のコマンドを叩くと、ポップアップが出てきてCLTのインストールができる

xcode-select --install

自分は手元に「現場Rails」の本を持ちながらインストールをしたのだが、次に以下のコマンドでxcodeがインストールされているか確認するように書いてあるので実行してみる。

xcodebuild -version

ところが、sudo xcode-select --switch /Path/to/CommandLineTools をしてください。と言われる。/Path/toの部分はさっきインストールされた先だと思うのだが、どうやって見つければいいのかわからない。

linuxのfindやMacのfinderでXcodeで探してみても見つからない...インストールはできたはずなのに、どこにいったんだ...

ここで色々調べて時間が飛ぶ

いろいろ探して下記のサイトをみつけた。

brew upgrade でのエラー対処からCommand Line Toolsについてまとめてみる|TechRacho by BPS株式会社

これによれば、/Library/Developer/CommandLineToolsにCLTがインストールされているらしい。 sudo xcode-select --switch /Library/Developer/CommandLineToolsを使えば、パスがつながるとのこと

これで再度

xcodebuild -version

それでもバージョンは表示されず、「これはコマンドラインツールです」みたいなメッセージが出る。

$ xcodebuild -version
xcode-select: error: tool 'xcodebuild' requires Xcode, but active developer directory '/Library/Developer/CommandLineTools' is a command line tools instance

さっきのサイトをよく読むと、xcodebuildはXcode本体のバージョンを示すそうなので、CLTしか入れてない今の環境では用のないコマンドだと言うことがわかった。

つまり、たぶんxcode-select --installの時点で動かせたのに、動かせてないと思い込んでたっぽい。早速brew doctorを実行してみる。なんかWarningが出るが、実行できている!

続いてrbenvの導入

brew install rbenv

最新のrbenvがインストールできたー!

やっった!!!!

余談

HomebrewのRubyとrbenvのRubyインストールが別の場所にされていることを初めて知った。 シェルを立ち上げるときに最新のRubyを参照するようにパスを通しておくことにする。

~/.zshrc

# HomebrewのRubyインストール先
# export PATH="/usr/local/opt/ruby/bin:$PATH"

# rbenvのRubyインストール先
export PATH=$HOME/.rbenv/versions/3.1.0/bin:$PATH
export GEM_PATH=$HOME/.rbenv/versions/3.1.0/lib/Ruby/gems/3.1.0

『The Art of Readable Code』のChapter15のコードをRuby化してみた

www.amazon.co.jp

現在、フィヨルドブートキャンプコミュニティで『The Art of Readable Code』の輪読会に参加しています。

日本語版と英語版どちらも開催され、日本語版の方は進みがよく、すでに輪読会は終了。

その際、最終章であるChapter15で、輪読会メンバーが「わけがわからないよ」と口々に言って半ば沈滞ムード気味になってしまったことがある。

主な原因はReadable Codeという書籍が一昔前の書籍であって、ブートキャンプメンバーが主力にしているRubyでは、殆ど当時の問題が解決されるようなアップデートが済んでいるからだと思われる。(コーダー側に依存していた問題が、言語側で解決されてしまった。)

はじめにJavaScriptJavaを使っていた自分にとっては、あるあるで頷く場面も多く、また、Rubyがいかに書きやすいかが改めて実感できたのだけれど...

また、この章は、他の章とは違って、通して動くような長いコードを書くことになる。コードはクラスごとに解説が入っていて、前後のコードの関連性や一気見した時の全体像がわかりにくくなっている。加えて、C++(たぶん)で書かれているので、手元でサクッと動かす環境がない人が多い。

以上のことを踏まえ、コードをRuby化して全体のコードを一つに繋げて実際に動かしてみたら、自分だけでなく勉強会の他のメンバーにも大きく貢献できると思ったので、書いてみた。

結局のところ、これを共有して他のメンバーの助けになったかどうかわからないが、とりあえず「なんとなくわかったかも」くらいの反応をいただけた。

最初はGistで密かに共有したのだが、どうやらこの本はコードの引用におおらかであるっぽいので、記事として公開することにしました。

下記コードをRubyで実行するとそのまま動きます。(確認環境: ruby 2.5.0)

(実行例)minute_hour_counter.rbというファイルに全部コピペして実行する

$ ruby minute_hour_counter.rb 

#=>
hour: 80
minute: 40
hour: 40
minute: 0
hour: 0
minute: 0

コード

# p222
# 後で書き加えられる
#
# A class that keeps counts for the past N buckets of time.

# class TrailingBucketCounter
#   def initialize(num_buckets: 60, secs_per_bucket: 0)
#     # Example: TrailingBucketCounter(30, 60) tracks the last 30 minute-buckets of time.
#     @num_buckets = num_buckets
#     @secs_per_bucket = secs_per_bucket
#   end
#
#   def Add(count, now)
#   end
#
#   ## Return the total count over the last num_buckets worth of time
#   def TrailingCount(now)
#   end
# end

# p223
class MinuteHourCounter
  # 動作確認のため時間を短縮
  # NUM_BUCKET = 60
  # MINUTE_BUCKET = 1
  # HOUR_BUCKET = 60
  NUM_BUCKET = 4
  MINUTE_BUCKET = 1 # 4秒
  HOUR_BUCKET = 2 # 8秒
  def initialize
    @minute_counts = TrailingBucketCounter.new(num_buckets: NUM_BUCKET, secs_per_bucket: MINUTE_BUCKET)
    @hour_counts = TrailingBucketCounter.new(num_buckets: NUM_BUCKET, secs_per_bucket: HOUR_BUCKET)
  end

  def Add(count)
    now = Time.now.to_i
    @minute_counts.Add(count, now)
    @hour_counts.Add(count, now)
  end

  def MinuteCount
    now = Time.now.to_i
    @minute_counts.TrailingCount(now)
  end

  def HourCount
    now = Time.now.to_i
    @hour_counts.TrailingCount(now)
  end
end

# p224
# 後で書き加えられる

# # A queue with a maximum number of slots, where old data "falls off" the end.
#
# class ConveyorQueue
#   ConveyorQueue(max_items)
#
#   # Increment the value at the back of the queue.
#   def AddToBack(count)
#   end
#
#   # Each value in the queue is shifted forward by 'num_shifted'.
#   # New items are initialized to 0.
#   # Oldest items will be removed so there are <= max_items.
#   def Shift(num_shifted)
#   end
#
#   # Return the total value of all items currently in the queue.
#   def TotalSum
#   end
# end

# p224

class TrailingBucketCounter
  # Calculate how many buckets of time have passed and Shift() accordingly.
  def Update(now)
    current_bucket = now / @secs_per_bucket
    last_update_bucket = @last_update_time / @secs_per_bucket
    @buckets.Shift(current_bucket - last_update_bucket)
    @last_update_time = now
  end

  def initialize(num_buckets: 60, secs_per_bucket: 0)
    @buckets = ConveyorQueue.new(num_buckets)
    @secs_per_bucket = secs_per_bucket
    @last_update_time = Time.now.to_i # the last time Update() was called
  end

  def Add(count, now)
    Update(now)
    @buckets.AddToBack(count)
  end

  def TrailingCount(now)
    Update(now)
    @buckets.TotalSum
  end
end

# p226

# A queue with a maximum number of slots, where old data gets shifted off the end.
class ConveyorQueue
  def initialize(max_items)
    # sum of all items in q
    @q = []
    @max_items = max_items
    @total_sum = 0
  end

  def TotalSum
    @total_sum
  end

  def Shift(num_shifted)
    # In case too many items shifted, just clear the queue.
    if num_shifted >= @max_items
      @q = []  # clear the queue
      @total_sum = 0
    end

    # Push all the needed zeros.
    while num_shifted > 0
      @q.push(0)
      num_shifted -= 1
    end

    # Let all the excess items fall off.
    while @q.size > @max_items
      @total_sum -= @q.first
      @q.delete_at(0)
    end
  end

  def AddToBack(count)
    Shift(1) if @q.empty? # Make sure q has at least 1 item.
    @q[-1] += count
    @total_sum += count
  end
end

# 以下、雑な動作確認
minute_hour_counter = MinuteHourCounter.new
# 1秒ごとに10を足す
# 8回繰り返す
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)
sleep 1
minute_hour_counter.Add(10)

puts "hour: #{minute_hour_counter.HourCount}"
puts "minute: #{minute_hour_counter.MinuteCount}"
sleep 4
puts "hour: #{minute_hour_counter.HourCount}"
puts "minute: #{minute_hour_counter.MinuteCount}"
sleep 4
puts "hour: #{minute_hour_counter.HourCount}"
puts "minute: #{minute_hour_counter.MinuteCount}"

Wordleというゲームが面白い

ここ数日の間に以下のようなツイートが流れていて、何かよくわからないけどオサレだなー、と思っていた。リンクとかが張ってないのでなんのことを言ってるのかよくわからない。

f:id:kasai441:20220108115524p:plain

 

UnderTaleのデザイナーであるTemmyが、これについて「いったい何なの?」とツイートして、そのリプ欄を見てはじめて、Wordleというゲームだということがわかった。

 

このゲームはシンプルな英単語の推測ゲームで、語彙力をためすのにちょうどいい難易度なのだが、ゲームそのものよりも特徴的なのが、その広め方である。

前述のようにゲームの結果ツイートにリンクなどが張られていないので、ゲームを知らない人には謎ツイートになっている。

ゲームは12時間に一回しかプレイできない。さらに、このゲームの答えは全ユーザー同じである。つまり、みんなで同じ問題を解くので、SNSでの共有に臨場感が生まれる。「自分は解けた」とドヤれる。これが結果ツイートをさせる動機となっていると思う。

リンクもないのでスパム扱いもされない。このやり方は新しいなと思った。あと、連続で何回もプレイできないので時間泥棒になってないのも好印象。

 

雪かき



東京の雪がこんなに積もるのは自分の記憶では4年ぶり。

 

4年前は親戚の空き家で一人寝泊まりしていたので、雪かきを自分でやるべきかいなか悩んで、ご近所あちこちの雪かき状況を確認して回った覚えがある。だいたい半々でやってるところとやってないところがあり、雪国出身の方はがっつりやっているのかしら?とおもったり。

 

雪かきをしないで放置して家の前が凍ってしまうと通行人も危ないし、車もスリップするので、夜のうちにかいておくのがベスト、みたいなことをネットで調べた気がする。

 

結局、4年前は翌日天気がとても良くなり、雪かきをしてない家の前もほとんど氷も残らず、取り越し苦労だったなあ、と感じた記憶がある。

 

今年は隣の家の雪かきが本格的で、こちらの家の前まですっかり夜のうちに綺麗になっていた。無責任ですみません、すごく助かりますー。

そういえば、Gitに飢えている

いま、スクールでGitの勉強をしているが、簡単ではない。簡単にプロジェクトのファイルをいじれるので壊すことも容易である。さまざまなケースを想定して動かさないといけない。いざ現場に入る前に覚えることがたくさんある。

リモートとローカルで別々にログやファイルが管理されるのも難しい。それらを同期するルールも難しい。履歴も細かくいじれるので、そのぶんやり方をたくさん知っていないと対応できない。現場によってどの機能をどのように使うかは違うと思うので、その場その場で対応するにはしっかりした基礎力が求められる。

Gitめんどくさいなー。とばしちゃおうかなー。そう思っていた私は、"はた"と、ある思いに至る。

そういえば私はGitに飢えている。

ファイルのバージョン管理はプログラミングに限らず、あらゆるオフィスワークに付きまとう問題と思う。毎日エクセルの資料ばかり作る事務職だった時、バージョン管理はファイル名でおこなっていた。「管理表200117.xls」「管理表200117_2.xls」「管理表200118_最新.xls」とかいうやつ。

やり方は属人的ルールに基づいているので、ファイル名をみたところで、どれを印刷したり改変したりしていいのかはわからない。ファイルを作った人に聞くしかない。最悪の場合作った人もわからないので、中身を見て判断するなり、細かい内容を一つ一つ確認しなければいけない。

ITエンジニアはGitという便利なバージョン管理ツールを使っている。一つファイルに対し、ツールが変更履歴をつけてくれる。フォルダごとに管理され、どのファイルをだれがいつ作ったもわかるし、テキストのどの位置を修正したかもわかる。だれか偉い人に改編の許可をもらうときもメールでいちいち説明キャプチャを張り付けたエクセル資料を作ってzip化してパスワードと別々に送信する必要もなく、直接改変のリクエストを送るシステムが備わっている。

私はプログラミングを勉強してITエンジニアを目指したとき、このGitさえあればいままでバージョン管理にかかわる大きな手間や失敗、試行錯誤などが一切必要なくなることに大きな期待をしていた。しかしいざエンジニアとして業務を始めると、この界隈でもGitを使わない会社がたくさんあることを知る。それも誰でも知っているような超大手メーカーのソフトウェアベンダーでもそうだった。いやむしろ、たぶん超大手だからこそGitを使わないのだ。Gitを使わない理由は知らない。比較的新しいものだから導入に踏み切れないのか、全員に強制的にやらせるのが難しいのか。

そのような現場体験を通して私はGitに飢えた。

それらの現場では、同じファイルを複数人がいじらないようにするというルールを基本としている。ただしこれも誰が何をいじっているかを何らかの書類で管理する必要があるし、工期が迫っていたりして一緒にいじる必要性が出てきたりする。その場合その時々で様々なルールが作られる。ファイルを細々と分割したり、色分けしたり、ファイル名で分けたりする。出たとこ勝負でなんとなく最終物ができる。マージを行う際にも各人が同じルールで作成していなかったりして、結局そのプロジェクトや人間間だけで特有の問題に対処するスキルが磨かれる。少なくともバージョン管理に関してはスキルアップしているとはいえない。

大きな問題は「デグレ」である。プロジェクトの途中でサーバ名が変わるとする。サーバ名を指定する箇所を修正する。同時にテスト工程が進んでいる。そのために最新のコードがテスト環境に送られる。そこで、一行だけ古いサーバ名のままだと判明する。その場で直して、テストは無事終わる。別の機能が追加される。別のテストが行われる。あれ?古いサーバ名が更新されていないほうのファイルで追加の機能が実装されているようだ...。次のテストでも同じところでプログラムが止まる。このような問題が、あとからあとから複層的に積み重ねられていく。テストを何度も繰り返すことはできない。テスト仕様書をながめながら、怪しいところを目視したりしてチェックする。おっともう納期が来た。えい、リリースしてしまえ。こんな感じである。

Git以外のツールを使ったこともある。Subversionというソフトだ。これを初めて使ったとき、デグレ地獄の現場から移ったばかりだったので正直感動した。みんなで同じファイルをいじっても大丈夫。どこの部分をいつだれが変えたかわかる。しかしこれは組織の問題だが、Subversionはリリースしたもののみを置く場所だという運用がされていた。開発中のファイルをアップロードしてはいけないのである。????なんでそんなことになっているのかわからない。過去に、開発中にリポジトリが全部消えたとか、何か障害があったのだろうか。しかしそのルールすら徹底していなかったので、チーム内でこっそりSubversionをつかっていたので開発はスムーズだった。ただし、そんな状況なのでIDをきちんと割り振られていない。みな同じIDを使いまわして開発していた。これはこれで問題がある。

さて、そんな状況だったのでGitをちゃんとつかっている現場というものに対する強い憧れが募っている。Gitに飢えている。

なんかめんどいので、適当におさえて現場で経験を積めば何とかなるかー、という怠け心をぐっとおさえて、そういえば自分はGitに飢えているのだったと思い返して、丁寧に勉強せねばと思い返す。

でも、多くの会社で浸透しないのは単純に難しいからなのかなー???