patorashのブログ

方向性はまだない

プリンシプル オブ プログラミング読書会を始めた

EffectiveRuby読書会が先週終わったので、今週からプリンシプル オブ プログラミング読書会を始めました。どういう本を読むのかは、チームメンバー3名で候補を出し合ってたのですが、これはパートナーさんが上げてくれた本で、「3年目までに身につけたい内容」ということで、ちょうど後輩氏にぴったりだし、自分も読んだことがないから良さそうだなと思って決めた次第です。

第一回では、本の内容についてと、前提、原則の途中まで進んだのだけれど、いろんな本に載っている内容を上手にまとめられている印象でした。沢山の本を読む手間が省けそうではあるし、節ごとに参考書籍の名前が載っているので、深堀したくなればその本を読めばいいというのも良さそう。

上ではAmazonで紹介していますが、今回は秀和システムの定額制読み放題の10xEngというサービスを使ってみました。

10x-eng.com

秀和システムの結構な量の本が月額990円で読み放題になっていて素晴らしい。もちろんプリンシプル オブ プログラミングもその対象。そして結構高額な本が多いし、システム系の本だけじゃなく、ビジネス書籍もラインナップに含まれています。ただし、本が探しにくい…。ジャンル毎に分けて合ってほしいところです。

とりあえず2週間無料でお試しできるようなので、他の本も読んでいってみようと思います。

RailsでElasticsearchを使う際のレスポンスはidだけ返せばよかった

表題の通りですが、今まで運用していて全然気づかなかったことでした。

Elasticsearchにクエリを投げると、ヒットした際にレスポンスがめっちゃ長くてdevelopment.logが見づらくなってました。 ログをよく見ると、レスポンスからrecordsメソッドを呼ぶと、ヒットしたデータのIDの配列でデータベースから再取得していたので、「あれ?これってもしかしてElasticsearchからのレスポンスってIDだけでいいんじゃない?」と思ったので、早速実験してみました。

ちなみに、これがその処理。

elasticsearch-rails/active_record.rb at v7.1.1 · elastic/elasticsearch-rails · GitHub

elasticsearch-dslでクエリを組み立てる

Postモデルがあるとして、Elasticsearchに既にデータ登録されているとします。 elasticsearch-dslを使って、sourceメソッドで取得フィールドを指定します。

definition = Elasticsearch::DSL::Search::Search.new
definition.query do
  # 検索条件を設定
end

# sourceメソッドで取得するフィールドを配列で指定する
definition.source([:id])

# ElasticsearchでヒットしたデータのIDから、データベースに取りに行く
posts = Post.__elasticsearch__.search(definition.to_hash).records

こうすると、ElasticsearchからのレスポンスはIDのみとなり、通信量が激減しました!😀はいえ、問題は、ちゃんとRailsで動くかどうかです。

テストの実行結果

担当プロジェクトのElasticsearch関連のテストを実行してみたのですが(見せられませんが…)、recordsメソッドでデータベースデータを取得し直しているので、テストも全て通って問題なし!しかもElasticsearchのレスポンスが減ったからか、テストの速度も若干改善しました🚀

Elasticsearchからのレスポンス自体を活用するには?

あんまりちゃんと調べてないけど、たしかrecordsメソッドではなく、resultsメソッドを使えばいいはず…。しかし、その際にはこの方法だとidしかないので、微妙です。でも、データベースへの問い合わせがないぶん、早いはず。ActiveRecordのモデルは使えないと思うけど。

elasticsearch-rails/response.rb at v7.1.1 · elastic/elasticsearch-rails · GitHub

画面で動作確認

本番環境と同等のマスタデータを搭載して、developmentモードで画面から検索をかけてみたところ、レスポンスが1秒近く改善しました。😯めちゃくちゃ効果あるやん…。1秒ではなかったです…。たまたま遅い時を引いてしまったぽかった。でもまぁ50ms〜150msくらい速くなりました。

まとめ

RailsでElasticsearchを使っている場合にrecordsメソッドを使っている場合は、Elasticsearchからのレスポンスはidだけあればいいので、idのみで取得しても問題なさそう。むしろ通信量が減って速度改善するしよさそう。

6月になってやっていること

先月のやつは、これ。

patorash.hatenablog.com

特に5月から代わり映えしていないのだけれど、継続して取り組んでいることは以下の通り。

  • EffectiveRuby読書会
  • モブレビュー
  • スプリントプランニング
  • レビューをする曜日を決める等

主に変更点はないのだが、他に取り組んだことを上げるとすると、以下の通り。 (あくまで私が率いるチームの、です)

  • 開発チームのルールを明文化した。開発チームのメンバーに求める資質なども。
  • 後輩氏とペアでRundeckのジョブを作成した。
  • プルリクのマージはプルリクを作った人が行うことにした。

開発チームのルールを明文化した

これは、まぁうちのチームに人が増えることは滅多にないのだけれど、オンボーディング的な資料にもなるし、自分たちでも確認しやすくするためにやった。暗黙的なルールよりは、オープンであるほうがいい。

求める資質については、ざっくりとは「自律的に動けるようになろう」と言いたかったのだけれど、それってどういうことか?を私の言葉で箇条書きしといた。

チームのメンバーに求めるもの

  • ミスを隠さない・ごまかさないこと
    • ミスは誰にでもあり得ること。チームでリカバリし、対策を練りましょう。
  • 問題を抱え込まないこと
    • 小さな問題だったら対処できるけど、問題が大きくなってからだと難しくなります。チームで早めに対処できるように動きましょう
  • 汚い言葉を使わないこと
    • その言葉を使った人自身のイメージが悪くなるだけ。良いことはありません。
  • わからないことをそのままにしないこと
    • 質問する、調査する、わかったことを共有する
  • 業務で得られた知見は情報共有すること
    • ドキュメント化する
      • 他のチームでも役に立つ情報かもしれません
      • なにより、自分のためになります
    • 汎用的な内容はブログ等で発信してもよいでしょう
  • 確認・確認・確認!
    • たとえ、相手に投げたボールが戻ってこなくても、返信することをうっかり忘れてしまっていることがあるので、適宜、再度確認をお願いしましょう
  • 自分で課題を見つけること
    • 言われたことだけをやるのではなく、自分自身で課題を探し、よりよくしていきましょう。

これらをまとめた言葉でいうと、 『自律的に動けるようになろう』 となります。

こんな感じ。特に、汚い言葉を使わないってのはすごく重視している。論理的に正しくても言い方がよくないと感情的な不和が起きてしまう。

後輩氏とペアでRundeckのジョブを作成した

これは、スモール・リーダーシップで書かれていた「一人でやらない」を実践した。無論、一人でやったほうが早いのだが、滅多にやらないことこそ、一人でやらずに後輩氏とやることで、後輩氏にとってのブラックボックスを減らすことができたと思う。今後、Rundeckのジョブを作ったり修正することが発生しても、後輩氏に頼むことができるようになった。

プルリクのマージはプルリクを作った人が行うことにした

これは、上司の id:tech-kazuhisa が、うちのTeamsに id:Songmu さんのGitのワークフローの記事の話題を投稿していて、それに感銘を受けたのですぐに採用した。まんまだが、私のレビューが通ればOKみたいな感じになっていたからである。

songmu.jp

以下は、開発チームのルールからの抜粋。

コードの管理はチームの責任であることが大前提ではあります。 しかし、○○さんがOK出したのでヨシ!というような人に依存する形はよくないというところと、 自分のコードがちゃんとプロダクトに反映されていくという当事者意識を持ってほしいからです。

以下は、そんむーさんのブログから抜粋した内容になります。

レビューとマージ

  • 社内プロダクト開発においてはpull requestを出した当人がマージボタンを押す
    • これは意見があると思うが個人的にはこだわりのスタイル
    • 「自分が押したマージが本番に出ていく」という体験をしてもらう
    • コードベースへの当人のオーナーシップの醸成
  • レビューを通して開発した当人が安心してマージボタンを押せる状況を作り出す
  • 「リードエンジニアにレビューしてもらってマージしてもらう」はアンチパターン
    • 暗黙の権威が生まれ、勾配も拡大する一方となる
    • レビューしてもらえたから大丈夫だろう、と担当者が油断する
    • レビュワーの好みにコード全体が偏る
    • さらにはレビュワーが過剰に直させる、みたいなことも起きがち
    • →コードベースが「リードエンジニアのコード」から脱却できない

6月のまとめ

基本的によかったことを継続している。EffectiveRuby読書会は月曜日に2時間くらいやっているので結構進んでいて、あと2回くらいで終わりそう。コードレビュー時の視点として、知っておいてよさそうなことが結構あったし、標準ライブラリの便利な使い方とかも知ることができたので結構得るものが多かった。

集中できる時間が増えたので、メンバーを育成しつつも、成果を出しやすくなってきた。

GraphQLの検索先をActiveRecordからElasticsearchに変更する

この記事はQiitaにも書いていますが、一応ブログにも同様のものを載せておきます。

qiita.com

graphql-rubyはリソースの参照元のデフォルトがActiveRecordなので、それをElasticsearchに変更したかったのですが、ライブラリがなかったので自分で実装しました。

環境について

  • Ruby 2.7.3
  • Rails 6.0.3.4
  • Gem
    • graphql 1.12.12
    • elasticsearch-model 7.1.1

実装方法について

GraphQLのページネーションは Relay-Style Cursor Pagination が主流でしょう。その他、kaminariなどを使ったページネーションの実装もQiitaの記事で紹介されていました。

https://qiita.com/nobuo_hirai/items/f9e34d8572a82283538b

こちらの記事にあるように、社内で使うだけとかであれば、kaminariのページネーションを使うのもありだと思うのですが、最終的に公開を目指しているAPIなので、素直にRelay-Style Cursor Paginationを使えるようにしました。

カスタムコネクションを作る

graphql-rubyは、デフォルトで様々なリソース用のコネクションクラスを準備しています。ActiveRecordだけでなく、Sequel、MongoDB、配列などをサポートしています。しかし、Elasticsearchはありません。そのため、独自にカスタムコネクションを作らなければなりません。

カスタムコネクションの作り方のサンプルは、公式のカスタムコネクションのページにざっくりとした作り方が書いてあります。

https://graphql-ruby.org/pagination/custom_connections

当初は、これを見ながら実装しようかと思ったのですが、やはりざっくりとしか書いてないので、なかなかわかりませんでした。そこで、graphql-rubyのpaginationsディレクトリのソースコードを読みながら進めることにしました。

https://github.com/rmosolgo/graphql-ruby/tree/master/lib/graphql/pagination

ActiveRecordRelationConnectionというクラスがあるのですが、それはRelationConnectionクラスを継承していたので、当初はRelationConnectionを継承して進めようとしましたが、よくわからなかったので、Connectionクラスを継承元とし、RelationConnectionで定義されているメソッドを全て再実装していきました。

結果的には、RelationConnectionで実装されているメソッドのままでよいものが大多数だったので、継承元をRelationConnectionに変更しましたが、処理の流れは掴めました。

それで、作成したクラスがこちらです。

module Connections
  class ElasticsearchRelationConnection < GraphQL::Pagination::RelationConnection

    def nodes
      @nodes ||= limited_nodes.records.to_a
    end
    # Rubocopにload_nodesメソッドが不要と言われた
    # しかし、継承元のRelationConnectionで呼ばれているのでnodesメソッドのエイリアスにしておく
    # また、元々private methodだったので変更しておく
    alias_method :load_nodes, :nodes
    private :load_nodes

    # GraphQL::Pagination::RelationConnectionの実装を改修
    # `@paged_node_offset`にオフセットが入っているので、2重で足さないようにした。
    def cursor_for(item)
      load_nodes
      # index in nodes + existing offset + 1 (because it's offset, not index)
      # offset = @nodes.index(item) + 1 + (@paged_nodes_offset || 0) + (relation_offset(items) || 0)
      offset = @nodes.index(item) + 1 + (@paged_nodes_offset || 0)
      encode(offset.to_s)
    end

    private

      # @param [Elasticsearch::Model::Response::Response]
      # @param [Integer] size LimitSize
      # @return [Boolean] sizeよりも残りが大きければtrueを返す
      def relation_larger_than(relation, size)
        initial_offset = relation_offset(relation)
        relation_count(relation) > initial_offset + size
      end

      # @param [Elasticsearch::Model::Response::Response]
      # @return [Integer] オフセットの値
      def relation_offset(relation)
        relation.search.definition.fetch(:from, 0)
      end

      # @param [Elasticsearch::Model::Response::Response]
      # @return [Integer, nil] 取得数
      def relation_limit(relation)
        relation.search.definition[:size]
      end

      # @param [Elasticsearch::Model::Response::Response]
      # @return [Integer] 総ヒット数
      def relation_count(relation)
        relation.results.total
      end

      # @param [Elasticsearch::Model::Response::Response]
      # @return [ActiveRecord::Relation]
      def null_relation(relation)
        relation.records.none
      end

      def limited_nodes
        super()
      rescue ArgumentError => _e
        # カーソルの先頭より前の要素を取得しようとするとArgumentErrorになったため、
        # 例外を補足して空のActiveRecord::Relationを返すようにした
        ApplicationRecord.none
      end
  end
end

これを使えるようにします。先ほど作ったコネクションを使えるように登録します。

class MySchema < GraphQL::Schema
  connections.add(Elasticsearch::Model::Response::Response, Connections::ElasticsearchRelationConnection)
  # 省略
end

そして、これを使ったスキーマを定義します。UserモデルのElasticsearchのスキーマ定義は省略します…。

module Types
  class QueryType < Types::BaseObject
    field :users, Objects::User.connection_type, null: false do
      argument :keyword, String, required: false # 検索キーワード
    end

    # **argsにすることで、graphqlのページング条件などを一手に引き受けさせる
    def users(keyword: nil, **args)
      query = Elasticsearch::DSL::Search::Search.new
      query.query do
        bool do
          if keyword.present?
            must do
              simple_query_string do
                query keyword
                fields ['keyword_search_field']
                default_operator :and
              end
            end
          end
        end
      end

      es_response = User.__elasticsearch__.search(query.to_hash)
      # 先ほど作ったコネクションで返す
      Connections::ElasticsearchRelationConnection.new(
        es_response,
        first: args[:first],
        last: args[:last],
        before: args[:before],
        after: args[:after],
      )
    end
  end
end

これで、Elasticsearchに対してGraphQLで検索させることができるようになりました。

実際にクエリを書いてみます。

query {
  users(keyword: "山田", first: 3) {
    edges {
      cursor
      node {
        id
        name
      }
    }
    pageInfo {
      startCursor
      endCursor
      hasNextPage
      hasPreviousPage
    }
  }
}

先ほどのクエリを実行した結果です(公開用にデータは適当に修正しています)。 pageInfoにカーソルの値や、前後のページの有無が返っています。

{
  "data": {
    "users": {
      "edges": [
        {
          "cursor": "MQ",
          "node": {
            "id": "34",
            "name": "山田 孝夫"
          }
        },
        {
          "cursor": "Mg",
          "node": {
            "id": "76",
            "name": "山田 孝之"
          }
        },
        {
          "cursor": "Mw",
          "node": {
            "id": "55",
            "name": "山田 太郎"
          }
        }
      ],
      "pageInfo": {
        "startCursor": "MQ",
        "endCursor": "Mw",
        "hasNextPage": true,
        "hasPreviousPage": false
      }
    }
  }
}

まとめ

  • graphql-rubyはデフォルトで様々なコネクションクラスを持っている
  • その他のリソースで検索させたい場合などはGraphQL::Pagination::Connectionクラスを継承して作ることができる
  • graphql-rubyでElasticsearchを使いつつ、Relay-Style Cursor Paginationを実現したければ、カスタムコネクションを作る必要がある
  • 上記に載せたElasticsearchRelationConnectionのコードが、それである。

Selenium WebDriverからCupriteへの移行は難しい件

この記事を読んで、SeleniumからCupriteに移行できたらテストがまた速くなるんじゃないか?と思ってここ数日動作検証してるのですが、思った以上にうまくいかないので、一旦移行を諦めようかなという気持ちになっています。

techracho.bpsinc.jp

とはいえ、今までやってきたことを何もメモに残さないのも勿体ないので、とりあえずそれらは今後のために残しておこうかなと。

バージョン情報

この記事の執筆時点での私の環境です。開発環境はDockerにしています。

  • Mac Catalina
  • Ruby 2.7.3
  • Rails 6.0.3.7
  • Capybara 3.35.3
  • Cuprite 0.13

Cupriteとは?

CupriteはCapybaraのドライバーで、Chromeを直接操作するCDPプロトコルを使えるFerrumを使ってブラウザを操作します。

cuprite.rubycdp.com

Selenium経由じゃない分、速いという話です。

設定類については、一番最初に貼った記事に説明があるので、そこらへんはここでは言及しません。

Cupriteへの移行に躓いた点

JavaScriptの実行方法がselenium-webdriverと違う

JavaScriptの実行方法が違ったため、wait_for_ajaxなどが動かなくなりました。Ferrumを使ってbrowserからevaluateメソッドやexecuteメソッドを使います。

# selenium-webdriver
page.evaluate_script('jQuery.active').zero?

# cuprite
page.driver.browser.evaluate('jQuery.active').zero?

まぁこの辺りは一括置換で対応できるので序の口です。

click_linkとclick_buttonがよくコケる

click_linkとclick_buttonが結構な頻度で落ちました。原因はfixed指定している要素の下に対象のリンクやボタンがあるからと言われました。いや、selenium-webdriverのときはそうならなかったし…。うちのプロジェクトでfixed指定している要素ってのはつまり、bootstrapのナビゲーションバーとかです。あと検索結果の件数表示とか。Cupriteよ、fixedな要素の下に行くまでスクロールすな!!という気持ちです。

仕方ないのでモンキーパッチをあてました。

def click_link(target)
  failed ||= 0
  super(target)
rescue Capybara::Cuprite::MouseEventFailed
  if failed.zero?
    # 固定ナビバーが重なってクリックできないケースがあるので、その際はナビバー分を移動して再度実行するようにした
    scroll_x = page.driver.browser.evaluate('window.scrollX')
    page.driver.scroll_to(0, scroll_x - 60)
  else
    # それ以外の場合に押せない場合は、検索結果のフッター要素が重なっているとみなして、最後までスクロールさせる
    page.driver.scroll_to(0, 9999)
  end
  failed += 1
  retry if failed < 3
end

これで、大体はクリックできるようになりました(が、例外拾ってるからコスト大きそう)

入力結果が反映されない

fill_inで入力してすぐにclick_buttonでsubmitしてるんですが、なぜかfill_inで入力した内容が反映されません。sleepかませるとうまく動いたのですが、そんなことしていたら速くなるわけがありません…。本末転倒です。それに何個fill_inするところがあるというのか…。

調べたら、:slowmoというオプションがあることがわかりました。コマンドを送る前に指定した秒数だけ遅延させるようです。試しに、0.1を指定したら、まともに動き始めました。

Capybara.register_driver(:cuprite) do |app|
  Capybara::Cuprite::Driver.new(
    app,
    **{
      window_size: [1200, 800],
      browser_options: remote_chrome ? {"no-sandbox" => nil} : {},
      process_timeout: 10,
      inspector: true,
      headless: !ENV['HEADLESS'].in?(%w(n 0 no false)),
      pending_connection_errors: false,
      slowmo: 0.1, # <= これ!
      timeout: 15, # <= これもないと割りかし落ちる…
    }.merge(remote_options)
  )
end

しかし、毎回の処理で0.1秒遅延させることになるので、こんなのしていたら相当遅くなります…。

現状でベンチマークを取る

結構ボリュームのあるシステムテストselenium-webdriverとcupriteでローカルで実行してみました。 cupriteは、上記の設定をしたままです。

結果、cupriteは10分。selenium-webdriverは6分という結果となり、圧倒的にselenium-webdriverのほうが速いということに…😅

これは別にcupriteが遅いということではなく、私のcupriteの設定が悪いという話ではありますが、じゃあ適切な設定の落とし所はどういう設定なのか?を手探りで探さなければならないしそれは辛い。

まとめ

2021年6月時点では、ちょっとcupriteにサクッと移行できるわけでもなさそうだし、しかもテストも速くなるための調整が難しそうなので、移行へのモチベーションが上がりませんでした。 しかし、テスト高速化はコスト削減にも繋がるので、引き続き、時々調査してみようと思っています。

「いやいや、そんなのしなくてもこうすればCupriteでイケるよ!!」という情報をご存知の方は是非とも教えてください!お願いします。

ジュニアNISAするしと思って投資の本を読んだ

ジュニアNISAの口座を開設して、震えながら現金を突っ込んでおきました。なんせ、突っ込んだお金は子供が大きくなるまで引き出せないのです。でもまだ何も買ってません。日経平均3万近いので、今年中に調整があって2万前後になるに違いない!!と思いながら、下がるタイミングが来るのを待っています。それまでに、どういう株を買っておくのがいいのかな?と色々と考えておりました。

完全に株主優待を貰える株に絞って選択していこうと思っていたのですが、AmazonKindleのセールで以下の本が出ていたので、買ってみました。今回はこれの感想です。

割安だからと飛びつくと痛い目に合う

はい、もう経験済みです。めっちゃ経験済みです。

かなり高かった株が下がってきて、値頃感あるし、上がるだろうからと買ってみると、全然上がらずそのままダダ下がりになってしまう件。いい会社かどうかの判断はちゃんとしましょうねってことです。じゃあどうやっていい会社かどうかを判断するのか?っていうのが、この本の内容です。

いい会社の条件

あんま書きすぎると本の内容になってしまうので詳しくは書かないけれど、ざっくり書くと、ずっと利益の出ている会社です。ずっと配当が出ている会社です。なんか当たり前のようで、当たり前ではないというか、当たり前のことができないのが初心者なんだろうなと読みながら思った。

著者は優秀な会社をスクリーニングして見つけられるツールを作って提供している会社の方なので、ポジショントークは多いけれど、著名な投資家はどういうところを見て投資しているか、その著名な投資家ですら、こういうところでミスをしたことがあるという話もあったりして面白い。

株で一発当てようぜ!みたいな感じではない。まぁそれは投資ではなく、投機ですね…。

指標として何をみるか

PERやPBRとか色々あるけれど、どういう指標を見ればいいかは業種による、という気づきがあった。自分が投資しようとしていた業界はPBRのほうが重要なんだなとかがわかったのはよかったです。

全体を通して

書いてある式とかはなかなか頭に入ってこなかったんだけれど、定量的に会社の価値を比べることで投資対象として適格かどうか判断するというのはあんまりできてなかったので、もっとしっかりと確認しようと思いました。雰囲気で株買ってたらあかんな…。

まぁ買ってしまうことはあるだろうけれど、どういう商売をやっているのか、PERとかはちゃんと見た上で判断していこうと思います。

5月になってやっていること

4月のことを、この前書いた。 patorash.hatenablog.com

もう3週間くらい経ってしまった。なかなかブログを書く時間も取れないほど、日々は慌ただしい。主に、家庭面で。まぁ岡山県も新型コロナの影響で緊急事態宣言が出てしまい、それもあって幼稚園が登校自粛になったりなど、色々あった。

まぁそれは置いといて。

5月になって取り組んでいること

前回の反省点を踏まえて、5月に取り組んでいることを並べる。

  • 週単位でのスプリントプランニング
  • アジャイルボード作り
  • Rubyに関する読書会を開いた
  • レビューする曜日を決めた
  • モブレビューをした

一つずつ紹介する。

週単位でのスプリントプランニング

まず、前回の反省で、細かなPRが沢山きてコードレビューだけで1日が終わってしまうという課題があった。 そこで、流量を決めるために、月曜日にスプリントプランニングを行うようにした。先のような課題はあるものの、簡単なプロダクトバックログであっても「急ぎではないが重要なこと」であったりするので、無闇に進める速度をゼロに落としたくはない。

ルールとしては、

  • 月曜日にスプリントプランニングする
  • 決められたプロダクトバックログを全てこなしたら、その週の仕事は終了とする
  • 残り時間は自己研鑽・技術調査・急ぎではないが重要なこと等に取り組んでもよい
  • あまりにチケット数を減らしすぎるのもよくないので、適度にアサインしてほしい
  • しかし、技術調査のために敢えて担当チケット数を少なくすることがあってもよい。それはスプリントプランニング時に要相談

とした。

アジャイルボード作り

弊社ではRedMineを使っているのだけれど、アジャイルプラグイン(?)が入っている。スプリントの設定を今までやっていなかったので、それを設定して週単位で見やすい形にした。

Rubyに関する読書会を開いた

コーディング力と、コードレビュー力を上げるために、Rubyに関する読書会を業務時間内にやりたいと考えていたので、それをメンバーに説明して、やることにした。お題の本は、Effecive Rubyにした。

Effective Ruby

Effective Ruby

これを選んだ理由は、私が読んだことがなかったことと、みんな初級の本はこなしているので、よりよい書き方にフォーカスしたかったからだ。メタプログラミングRubyだと妙なテクニックに走りかねないかも…という懸念もある(第二版はまだ読んでないが)。

とりあえず今月は今のところ2回やっている。週に1回のペースでやっていく。

レビューする曜日を決めた

PRの量を調整したところで、毎日のようにレビューがあるとスイッチングコストが大きくなってしまう。それは他のメンバーもそうだと思うので、レビューする日としない日を決めた。

曜日 やること
月曜 打ち合わせ、読書会、残りはタスクに取り組む
火曜 タスクに取り組む(相談はOK)
水曜 モブレビュー、残りはタスクに取り組む
木曜 タスクに取り組む(相談はOK)
金曜 モブレビュー、残りはタスクに取り組む

水曜と金曜をモブレビューの日にして、火曜・木曜を動けるようにしたので、とりあえず集中して作業できる日が確保できたので、ある程度進捗を出せるようにもなった気がする。とはいえ、これはあくまでも開発チームとしての決まりごとなので、他のチームからの問い合わせには柔軟に対応している(データ出してー、とか)

モブレビューした

モブレビューは、モブプログラミングみたいに、ワイワイとチームでレビューする会である。オンライン会議で画面共有しながらレビューをするので、どういう意図でこう実装したのか聞いたり、より良いコードはこう、とか、歴史的経緯でこう実装されているという話をメンバー全員に共有できるので、話が早い(まぁ私含めて3名だけど)。PR作成者に実際の動作を画面共有しながら見せてもらうこともできるので、こちらで下準備する手間とかもない。

また、指摘のほうが間違っている場合にも、即座に反論というか意見交換できるのでレビュワーが勘違いしてた場合も助かる(主に勘違いするのは私)。

本来の目的は、ベテランの視点でのレビューで指摘されるところをメンバーに共有して、若手のレビュー力を向上することにあるのだが、週報のときに感想を聞いてみたら、「文字だけで指摘されるよりも腑に落ちやすい」ということだった。

まとめ

これらの取り組みによって、

  • チームのRuby力の向上
  • チームのレビュー力の向上
  • 割込を少なくして開発効率を上げる
  • 自己研鑽・技術調査をタスクに入れてもいいと認識してもらう

というところを狙っている。

個人の力量が上がらないことには、チームの力量も上がらないので、私としては、まずはチームとしての力を底上げしつつ、各々が自分の好きな技術分野で得意を増やしていってもらえたらなあ、と考えている。