SmartHR Tech Blog

SmartHR 開発者ブログ

SmartHRでのメタプログラミングRuby読書会と、その成果物

エンジニアのkinoppydです、お久しぶりです。 今日は社内メタプログラミングRuby 第2版読書会を開催した話と、その成果物に関して共有しようと思います。

SmartHR社内での勉強会

社内では、いくつかの勉強会や読書会が開催されています。業務で必要な知識をみんなで揃って学習する目的であったり、単に有志で集まって自分たちの力を底上げするためにやっていたり様々な形態のものがあります。例えば直近では、大規模スクラムを実践するために、大規模スクラム Large-Scale Scrum(LeSS) アジャイルとスクラムを大規模に実装する方法をテキストにスクラム勉強会をCTOのmasato_serizawaが開いていたり、フロントのコードを書くときのメンタルモデルを学ぶためにDan AbramovのJust JavaScriptを毎週翻訳して参加者で共有する会を、フロントエンジニアのnabeliwotokkyが開いていたりします。

メタプログラミングRuby読書会は、もともと私が好きで開いていたSinatraコードリーディング会やActiveRecordコードリーディング会の中で、意外とこの本を読んだことがある人が少ないことに気づき、名著なのでぜひ読みましょうということで開催しました。

読書会の開催スタイル

読書会、色んなスタイルがあると思います。一番単純なのは輪読会で、参加者で集まって本を黙々読んだり、あるいは一人が代表して読み上げたりするスタイルだと思います。一番ハードなのは、全員で本に関するまとめを作成し、互いにプレゼンしあって全員の認識をまとめていき、出題された課題を解くという大学のゼミみたいなスタイルかなと思います。

今回メタプログラミングRuby読書会を開くにあたり、主催の私は次のような点を考慮しました。

  • 前提として、みな業務があるので必要以上に業務時間は圧迫できない
  • 全員のレベルが揃っているわけではないので、十把一絡げに話を進められない
  • ただ読むだけで効果が無いとは言わないが、エンジニアリングに活かせるレベルに持っていきたい

つまり、ハードなゼミみたいな事はできないけど、のんびりとした輪読会にするわけにもいかない、ということで中間点を探る必要がありました。その上で、実施のスタイルは次のような形にしようと考えました。

  • 開催は週に一度
  • 参加者をレベル分けする
    • メタプロの修行僧と、既に本を読んだことがあったりメタプロに精通しているヌンチャク使い、そして講師になれるマスター・老師
  • 学習をしてほしいのは修行僧なので、毎週修行僧から誰か一人を乱択し、次回の学習内容を簡単にまとめてもらう
  • そしてヌンチャク使いからも一人乱択し、その内容をレビューを行い、開催の一日前までに完成させる
  • 読書会の当日に、主催者である私がまとめられたテキストを使って本の内容を全員に講義する

ただし、この方法では実際にテキストの要約を任された修行僧と、それをレビューするヌンチャク使い以外はあまり内容が身に入ってこないと思いました。日常の業務をこなしながら読書会にコミットし続けるのは大変です。そこで、これに加えてエンジニアリングに活かせるレベルの知識を得るために、次のことを行いました。

  • マスター・老師は、講義の内容からコーディング問題を作成する
  • 具体的には、「こういう仕様を満たすクラスを作成してほしい」という日本語の仕様書と、それをチェックするテストコードを用意する
  • それらをGitHub上で公開し、参加者にForkしてもらい、GitHubActionでCIを通過させることで、その講義は修了となる
  • このコーディング問題は、修行僧/ヌンチャク使い/マスター・老師問わず全員が解く

このように、講義のあとに実際に手を動かす問題を用意することで、参加者全員がメタプログラミングRubyと向き合い、修行僧には確かな実力を、ヌンチャク使いには新たな発見を、マスター・老師には問題を作り上げるという鍛錬を積むことができます。加えて、TDD的な開発スタイルを模倣した問題となっているので、テストを書く重要さも感じられるかと思いました。

また、作成した問題はGitHub上で公開し、誰でも挑戦できるようにしました。後述しますが、問題を作成するのにはかなりコストがかかり、うちの読書会でもやってみようと真似するには結構な重労働でもあります。そのため、我々の成果物を広く公開することで、気軽に他の人達にも真似してほしい、そして何かもっとよくできる点があればプルリクエストを送ってほしい(例えば、エッジケースのテストの追加や、もっと良い問題の追加など)、という考えです。

成果物

SmartHRで使った問題は、このリポジトリに集約されています。 kinoppyd/reading-metaprogramming-ruby

このリポジトリの目的は、READMEにも書かれている通り、Forkしてブランチをきり、常にCIがグリーンであることを目指すというものです。SmartHRで実施していたときは、毎週問題が追加されていたのでテストを通し続けることを目的にしましたが、今はすべての問題が追加されているのでグリーンにすることそのものを目的にしていいと思います。

試しに、問題のうち一つを見てみましょう。まず、リポジトリのルートにメタプログラミングRubyの各章に合わせた名前のディレクトリが用意されています。今回は、 02_object_model の一つである hierarchy.rb から一つ問題を見てみましょう。これは、メタプログラミングRubyの2章にあるオブジェクトの継承に関する問題です。ちなみにこの問題は、コミットを見れば分かる通りマスター・老師であるmeganemuraが作っています。

hierarchy.rb at master

# Q5.
# 次の動作をする M1Refinements module を実装する
# - M1Refinements は M1 の name インスタンスメソッドをリファインし,
#   リファインされた name メソッドは "Refined M1" を返す
# - C5.new.another_name が文字列 "M1" を返す
# - C5.new.other_name が文字列 "Refined M1" を返す
module M1
  def name
    'M1'
  end
end

module M1Refinements
end

class C5
  include M1

  def another_name
    name
  end

  using M1Refinements

  def other_name
    name
  end
end

本当はM1モジュールの定義はファイルの先頭にあるのですが、見やすいように移動しています。このように、日本語で書かれた仕様を満たすコードを書く問題です。そして、この仕様を正しく満たしているかのテストが同梱されています。 test ディレクトリの下に、各問題のテストが用意されています。今回は、 test/02_object_model/test_hierarchy.rb がそれに該当します。

test_hierarchy.rb at master

  def test_c5_another_name
    assert_equal "M1", C5.new.another_name
  end

  def test_c5_other_name
    assert_equal "Refined M1", C5.new.other_name
  end

この二つは日本語で書かれた仕様をほぼそのままテストに落とし込んでいます。この二つのテストをパスすることで、先程の問題をクリアしたということを確認できます。

このように、SmartHRのメタプログラミング勉強会では、読書会の内容を確認できる問題を成果物として公開しています。またこの問題集になにか問題やテストを追加したくなったら、ぜひプルリク送ってきてください。SmartHRの技術顧問であるwillnetさん経由で、willnetさんが顧問をされている他の会社でも利用されているそうです。ぜひ皆さんもメタプログラミングRubyの読書会を開催する際には利用をして、みなさんの学習の役に立ててください。そしてこのリポジトリにコントリビュートしてくれると嬉しいです。

開催してみてわかったこと

まずポジティブな話からですが、概ね読書会は好評だったと思います。毎回必ず問題が出題されるので、それを私やマスター・老師たちが質問を受け付けながら各自解いていくというスタイルでしたが、みな真剣に問題と向き合っていました。一方で、質問を受けることはあまりなかったので、もっとライトに質問できる方法を模索する必要はあったかもしれません。修行僧の方々からの意見としては、一人で読んでも難しかった本に立ち向かっていくにはとても良い環境だったと評判をいただきました。

ネガティブな面ですが、実はもうちょっと簡単に開催かなと予想していましたが、実際は決してライトとは言えない、重めの読書会になっていました。特に、問題作成を行うマスター・老師たちにかなりの負荷がかかる結果となりました。また、テキストをまとめる側も決して楽な作業ではなく、そのレビュアーも業務時間の中で勉強の時間を作り出すのに苦労を強いてしまいました。そのため成果物のリポジトリは、様々な人が頭を捻って作り出した汗と涙の結晶です。

いくつかの振り返り

ここからは、問題付きの読書会を開催して気づいた知見を簡単にまとめておきます。

まず驚いたのは、意外とみんな日本語の仕様書をちゃんと読んでいるということでした。TDDスタイルだったので、仕様の正しさはテストが最も優先されるため、もっとみんなテストの方ばかり読むかと思っていました。ですが、想像以上に日本語の仕様書を優先して読むひとが多かったです。そのため、すこし雑や曖昧に書かれている仕様の箇所に関して、読み違いや不十分な説明のせいで、問題の難易度を不必要にあげてしまっている箇所がありました。毎回「曖昧なところはテストを見てください」とアナウンスしていたのですが、やはりドキュメントというものの力は強いのだなと改めて思い知らされました。

問題付きの読書会では、定期的な振り返りが必要だということもわかりました。一度、どうしても開催の日に休む必要があった際、willnetさんに今までの問題の振り返り会を急遽お願いしたことがあります。その結果、問題は解けていたけれどその内容に納得していない人たちからの反響が大きかったと聞きました。Rubyは一つの問題にいくつもの解決策を用意できる言語なので、出題者の意図や模範解答などを示すことも、一つの重要な学びだったということがわかりました。

テキストのまとめとそのレビューをどこで行うかも、結構重要な問題でした。最初はテキストの管理もGitHub上で行っていたのですが、そもそも著作物である本の要約を公開すること自体に問題があるという意見があり、実際そのとおりだと思ったので途中から公開を取りやめました。そして、それ以降は社内のesaで要約を管理し、レビューしていました。ところが、今回の参加者は全員同じ会社に所属していたので、会社のドキュメンテーションツールが使えるのですが、そうでない人たちが集まった勉強会はどうなるんだろう? という疑問が僅かに残りました。また、個人的には要約とレビューも勉強会の成果物なので公開したかったのですが、法的に公開できるわけもなく、修行僧とヌンチャク使いの頑張りが外向けに報われないのは少し残念でした。

SmartHRで勉強会を開くということ

ここからさきはもう予想通りだと思いますが、求人です。SmartHRでは、このような読書会のテキストなども、全員分会社の経費で買ってくれます。その判断も、CTOに「いい?」って聞いてCTOが「いいよ!」って言ったらOKです。勉強会の開催も特に制限はなく、広いセミナールームも完備しているので、ワレこそは勉強会を開きたいぞという人にもいい環境かなと思います。また、別に開きたくはないけど聞きたいという人にもオススメです。

まずは気軽にカジュアル面談から始められるので、ぜひ皆さんに興味を持っていただければと思います。

hello-world.smarthr.co.jp

めんどくさいなぁと思ったら、直接私のTwitterアカウントにDMくれても大丈夫です。