esm アジャイル事業部 開発者ブログ

永和システムマネジメントアジャイル事業部の開発者ブログです。

Ruby-Docへのフィードバックについて

新卒氏ズのひとりのスワンプ氏とランチを食べながら、「るりま」のサンプルコードプロジェクトでの活動の話を聞いていたりした。

github.com

その際に「るりま」を元にしたものを Ruby-Doc にフィードバックするにはどうしたらという話があったのでその事例を紹介する。

以下は以前に Module#constants について「るりま」と Ruby-doc 両方にフィードバックした際の PR となる。この時はまず Ruby-Doc に送ってから「るりま」に送っていたが話としては類似したものだと捉えている。

ので GitHub に慣れているようであれば ruby/ruby をフォークして PR を送るのが良いだろう。

リモート勤務を始めて10ヶ月経ちました

こんにちは、富山在住の kunitoo です。

リモート勤務はじめましたにもありますが、昨年12月20日から出身地である富山県に引っ越し、リモート勤務という体制で働き始めました。 約10ヶ月間リモート勤務を行なった感想は、スムーズにリモート勤務に移行でき、 日々の業務も問題なく進めていけたと感じています。

リモート勤務を実施する中で、事前にやってよかったことや工夫してみてよかったことについてまとめました。

リモート勤務をこれから始める人や、既に実施している人の参考になればと思います。

よかったこ

  • リモート勤務をはじめる前から東京での在宅勤務が定着していた
  • プロジェクトを変えずにリモートに移った
  • マイクスピーカーを拠点ごとに用意した
  • Idobata 等の通知にすぐに反応できるようにした
  • ビデオチャットを気軽に接続できるようにした
  • 家族に「いってきます」「ただいま」を言うようにした

リモート勤務を始める前から東京での在宅勤務が定着していた

弊社にはリモート勤務が始まる以前から在宅勤務制度があり、富山に引っ越す以前から私自身も週に1、2回程度、在宅勤務を行っていました。 多くの人が在宅勤務を行っていたので、在宅勤務のメンバーがいるという状況に慣れていたため、突然私だけが出社しなくなり業務に大きく影響出るということが発生しなかったように感じます。

プロジェクトを変えずにリモートに移った

リモート勤務に移るタイミングでプロジェクトを移るということはありませんでした。 チームメンバーが変わらないので、コミュニケーションの面で変化が抑えることができ、リモートだから上手くいかないのか、リモートじゃなくても難しい問題なのかを切り分けることができたのではないかと思います。 うまく伝わらないなーと思ったときに、出社している時にはどのように伝えていたかというのもヒントにできました。

マイクスピーカーを拠点ごとに用意した

朝会や会議、ペアプロなどでビデオチャットを利用しているのですが、その際に重要になるのが音声品質です。 とくにマイクの性能がよくないと気付かない間に、相手に聞こえなかったり、不快な思いをさせてしまいます。 しゃべっている側は音声品質が悪いことに気付きづらいので、気を使う必要があると感じました。 また、マイクスピーカーを利用することで、スピーカーの音をマイクが拾ったり、イヤホンをしなくても長時間会話できるため、私は気に入っています。

今回はプロジェクト専用として東京側に複数人の声が拾える ヤマハ YVC-300 を購入し、富山には ヤマハ PJP-10UR を購入しました。

Idobata 等の通知にすぐに反応できるようにした

Idobata でメンションがあったときにすぐに反応できるように、私はスマートウォッチ(Pebble Time Round)を利用して、仕事中に必要そうな通知だけに絞り込むことで、すぐに気付けるよう工夫しました。 これによって、となりの席にいるような、「今ちょっといい?」というような会話のスタートが切り易くなり、常時ビデオチャットを繋がなくてもよい環境が作れています。 常時ビデオチャットを繋がないことで、会話のないときの作業に集中できたり、会話するときにメリハリが生れるといった効果があったと感じています。

最近ではプロジェクトで利用する appear.in のルームを決めているため、"@kunitoo appear.in?" といったメンションが来たタイミングでスムーズにビデオチャットをスタートすることができています。

ビデオチャットを気軽に接続できるようにした

事業部の会議や勉強会などにリモートから参加する際に、なにで繋ぐかというのを Idobata でやりとりするところからスタートしていることがありました。 現在は関連する Idobata のルームの Description に接続先 URL を記載し、時間になったらその URL にアクセスするという運用を行っています。
これによって私だけでなく、在宅勤務の人も会議に参加し易い環境になったと思います。

f:id:kunitoo:20170909165148j:plain

家族に「いってきます」「ただいま」を言うようにした

今回引っ越しするにあたって(家族の同意を得て)仕事部屋が確保できる間取りのアパートを選びました。 リビングから仕事部屋に移動する際に「いってきます」といい、リビングに入る際に「ただいま」と言うようにしました。
これは、自分の仕事モードへのスイッチのつもりで始めましたが、妻にも影響があり、仕事中は集中できるように気を使ってもらえているようです。

まとめ

私の場合はリモート勤務に移行するにあたり、大きな変化がないようにしたこともあり、仕事には大きな影響はありませんでした。 できるだけ変化を抑えつつ、コミュニケーションツールに気を使えば、リモートワークのハードルは下っているように思います。

少しでもリモート勤務を行う人の参考になれば幸いです。

事業部メンバーで合宿に行って、モブプログラミングを体験しました。

7/6(木)~7(金)に事業部メンバーで合宿に行ってきました。 アジャイル事業部では毎年1~2回、合宿を計画してメンバーが参加します。 過去には「チームビルディング」や「自分たちが大切にしていることを探す」などのテーマでも実施しました。 ここ数回は、「(主に業務で使用しない)技術で遊ぼう」ということで、「IoTハッカソン」や「日々の生活を便利に」をテーマにプログラミングや電子工作にチャレンジしています。

f:id:m_pixy:20170707073218j:plain

今回は以下のコンテンツで一泊二日を過ごしました。

  • オフラインリアルタイムどう書く
  • 事業部計画書を読む会
  • バーベキュー
  • モブプログラミング

今回の会場は、桐花園という神奈川県のキャンプ場でした。 (http://tokaen.jp/) 私たちの合宿では初使用でした。本当に普通のキャンプ場なのですが、センター棟と呼ばれる建物は合宿所のような作りで、広い作業場所兼宴会場となった和室は使い勝手が良かったです。開発合宿先を探している方には候補のひとつとしていただければと思います。

オフラインリアルタイムどう書く

オフラインリアルタイムどう書く(以下「どう書く」)は、与えられたお題に対して1時間かけて解くイベントで、パブリックな場所では 横浜へなちょこプログラミング勉強会 | Doorkeeper で開催されています。 アジャイル事業部では、このイベントに会場提供をしていたり、社内勉強会として開催したりしています。 今回の問題は、「6×6のマスを、指示された通りに移動して、移動した終点の文字を出力する」というお題でした。(当日のお題はこちら 第37期合宿 どう書く 問題 · GitHub

f:id:m_pixy:20170711193442j:plain

若いメンバーがどんどん解答していく中、普段あまりコードを書いていない僕も必死でプログラミングしたものの、時間切れでした。 みんなが解答を出した後は、それぞれが自分の考え方や書いたコードを発表して、「あー、そんなやり方があったかー」と悔しい思いをしたり、「これはもっとうまくやれるはず」と上から目線になってみたり、楽しい時間を過ごしました。

事業部計画書を読む会

8月から新しい期が始まるのに合わせて、できたてホヤホヤの事業部計画書をみんなで読みました。なかなか普段は意識しない計画書の内容について、ああだこうだと意見を交わす貴重な時間でした。

バーベキュー

1日目の夕食は、バーベキュー。火を起こして、用意してもらった肉や野菜、焼きそばを焼いて、みんなで食べました。お酒を飲みながらということもあり、いろいろな場所で話が盛り上がっていました。

モブプログラミング

2日目は朝からモブプログラミング。2グループに分かれて、与えられたお題に沿ったソフトウェアを作ります。普段仕事で使っているRubyや、使える人が多いJavaを禁止して、あまり使ったことがない言語から選択します。さらには普段よく使うHerokuや、AWSなどは使用しないというルールで開始しました。 1チームはScala、もう1チームはPythonを選択しました。そして両チームともインフラはほぼ初挑戦の人が多かったGCPを選択。

f:id:m_pixy:20170707135802j:plain

両チームとも苦戦しながらも、みんなでシンタックスを調べたり推測したりしつつ、少しずつものが出来上がっていく過程を楽しみました。個人的にはPythonはまったく書いたことがなかったのですが、ドキュメントを調べながら初挑戦の言語で動作させていくことを楽しめました。また、「この人はこういう状況にハマった時にこういう試し方をして確認するんだなー」等、同僚の行動を見ることができたのも面白い体験でした。

RedDotRubyConf 2017 に行ってきました

こんにちは@color_boxです。 6/22 - 6/23 にシンガポールで開催されたRedDotRubyConf 2017に参加してきました。 今日はカンファレンスに参加した感想を書こうと思います。

f:id:color_box22:20170622091959j:plain:w480

シンガポール

今回の参加者は @muryoimpl@yucao24hours@color_box、 引率の @kakutani の計4名です。

今回の旅費はアジャイル事業部から出してもらっています。🙏🏼

本編

実際の発表で使用されたビデオやスライドはこちらです。

弊社顧問の@a_matsudaRubyの新機能とRailsに関する基調講演Rubyのしくみをベースにネットミームとイラストを交えておもしろおかしく紹介した発表巨大なRailsのアプリケーションの開発速度をいかに維持するかの工夫に関する発表 など、興味深い発表が盛り沢山でした。

個人的に興味深かったのは、巨大なRailsのアプリケーションの開発速度をいかに維持するかの工夫に関する発表でした。 Shopify のような大きいサービスになると開発のためのオーバヘッドは決して無視できない大きさになります。 それを減らすための工夫が重要になるという点が興味深かったです。

英語

すべての発表は英語で行われたため、聞き取り能力が試される時間でもありました。

スライドに情報が多いタイプの発表は聞き取りができなくてもかろうじて意味は読み取れます。 しかし、スライドに情報が少ないタイプの発表だと聞き取りができないと読み取れる意味が少なかったり間違っていたりするため、その点は苦労します。

また、他のエンジニアの方と話すときも基本は英語です。 なので、ここでは聞き取り能力だけでなく、発言する能力も試されます。

英語のヒヤリングやコミュニケーションに今後の課題があると感じました。

その他

食事

カンファレンス参加中は朝食とランチが提供されます。 東南アジア特有の料理が多くどれも美味しかったです。

f:id:color_box22:20170623091151j:plain:w480

まとめ

国内でのカンファレンスとは雰囲気が少々異なるカンファレンスでした。 英語などの障壁もありますが、学べるものは多かったです。 何より、今回シンガポール渡航したことで海外へ行く心理的なハードルが下がりました。 今後も機会があれば参加してみようと思います。

最後になりましたが、引率をしてくださった弊社顧問の角谷さん。 シンガポールへの渡航費、宿泊費を負担してくれた弊社アジャイル事業部に深くお礼申し上げます。

ありがとうございました。

LTをしている方達を見て、次は自分もやってみようと思う @color_box でした。

それでは

GentooInstallBattle on ThinkPad X1 Carbon 5th Generation

こんにちは、hibariya です。さいきん会社支給のマシンを買い替え、ThinkPad X240 から X1 Carbon (5th) になりました。Gentoo Linux のインストールをするのは約2年ぶりです。いつも通りちょっと大変でしたが、無事に新しいマシンから記事を書ける状態になりました。

さっそく次回のインストールへの備えも兼ねて今回の記録を残しておきたいと思います。だいたいは公式のハンドブック過去に残していた記録を参考にしてさくさく進んだので、ここでは前回と違うところ、特にカーネル周りの設定をどうやったかについて書きます。

カーネルのビルド

前回までは、関係がありそうな設定はひとまず有効にしておくという割とおおざっぱなやり方でビルドしていましたが、本来何が必要だったのかが曖昧になっている状態というのは少し不安です。今回はもう少し丁寧に、なるべく必要なものに絞ることにしました。しかしカーネルの設定をちゃんとやろうとすると、どうしてもちょっとめんどうで難しそうな印象があります。

Manually configuring a kernel is often seen as the most difficult procedure a Linux user ever has to perform. Nothing is less true - after configuring a couple of kernels no-one even remembers that it was difficult ;)

Gentoo Linux amd64 Handbook: Installing Gentoo - Gentoo Wiki

実際には、何が必要かは少し調べるとだいたいあたりがつきますし、手数は多いものの設定の項目自体は (思っていたよりは) それほど多くありませんでした。

おおまかな流れとしては、まず make defconfig でデフォルトの設定を生成し、そのうえで必要そうなものを有効にしていきます。

flaggie sys-kernel/gentoo-sources +symlink
emerge gentoo-sources
cd /usr/src/linux
make defconfig
make menuconfig # 追加で必要そうなものを設定
make -j3 && make install && make modules_install

以下のドキュメントと、 lspci lsusb dmesg などの出力をあわせて参考にしつつ、内蔵デバイスのサポートを追加していきました。

最終的には、デフォルトの設定に加え次のような設定を有効にしました。ストレージの接続規格が NVM Express になっているので、それも有効にしています。

  • NVMe
    • NVM Express block device (BLK_DEV_NVME)
  • Network
    • Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) (IWLWIFI)
    • Intel Wireless WiFi MVM Firmware support (IWLMVM)
  • USB
    • Battery level reporting for HID devices (HID_BATTERY_STRENGTH)
    • Lenovo / ThinkPad devices (HID_LENOVO)
    • xHCI HCD (USB 3.0) support (XHCI_HCD)
    • Generic xHCI driver for a platform device (USB_XHCI_PLATFORM)
  • UEFI
  • Systemd まわり
    • systemd (GENTOO_LINUX_INIT_SYSTEMD)
    • Built-in kernel command string (CMDLINE) root=/dev/nvme0n1p3 init=/usr/lib/systemd/systemd psmouse.proto=imps
  • 音の入出力
    • Enable generic HD-audio codec parser (SND_HDA_GENERIC)
  • 内蔵カメラ
    • USB Video Class (UVC) (USB_VIDEO_CLASS)
  • ACPI

ひとまず GUI やインターネットが使えるようになったところで、この段階ではまだ Docker や VirtualBox などは入っていません。とはいえ、ここまでくればだいたい山場は越えたと言ってよさそうです。

落とし穴

上記ではカーネルパラメータとして psmouse.proto=imps を渡しています。これは Systemd とは関係なく、ポインティングデバイスがうまく動作しない問題の workaround です。UEFI firmware をアップデートする、Track Point を無効にするなど色々やってみましたが、手元のマシンではこの方法に落ち着きました。

ThinkPad X1 Carbon 5th Gen

ロケールをデフォルト (ISO-8859-1) のままにしていたら gnome-terminal が立ち上がらず、ちょっとハマりました。en_US.UTF-8 に変更して無事立ち上がりました。

その他

cpuid2cpuflags で CPU の最適化フラグを設定しました。

$ emerge app-portage/cpuid2cpuflags
$ cpuinfo2cpuflags-x86
CPU_FLAGS_X86="aes avx avx2 fma3 mmx mmxext popcnt sse sse2 sse3 sse4_1 sse4_2 ssse3"
$ cpuinfo2cpuflags-x86 >> /etc/portage/make.conf

おわりに

これまで割と適当にやっていたカーネルの設定についてやったことを書きました。よりよいやり方があればぜひ教えてください。

graphql-batch でバックエンドへのクエリを減らす

こんにちは、hibariya です。最近 ミートアップ が開催されるなど、GraphQL が静かに注目を集めていますね。GraphQL は Web API で使えるクエリ言語です。GraphQL 自体は特定のデータベースに依存しないため、RDBMS を使ったアプリケーションで採用することも可能です。PostgreSQL を使う Idobata でも GraphQL の Public API を公開しました。GraphQL 自体がどういうものかについては、graphql.org や以下の資料が参考になるのではないかと思います。

GraphQL でサーバ側を実装するときに起こりがちな問題として、クライアントから投げられるクエリによっては RDBMS への問合せが大量に発生してしまうというものがあります。今回は RubyRails でこのような問題に対処する方法について書きます。

チャットアプリの例を使いたいと思います。次の例は、ログインしているユーザ (viewer) が閲覧できる発言 (message) の一覧と各発言が投稿されたチャットルーム (room) の名前を取得する GraphQL のクエリです。それぞれ、一対一に対応する Active Record のモデルがあるとします。

query {
  viewer {
    # a message belongs to a room
    messages(first: 10) {
      body
      room { name } # message.room による問合せが最大10回
    } } }

特に工夫をしなければ、room { name } を取得する SQL は message の数だけ DB に投げられてしまいます。Ruby で表現すると次のようなイメージです。

Message.readable_by(current_user).limit(10).map {|message|
  # message.room が10回
  {body: message.body, room: {name: message.room.name}}
}

次の例は、あるチャットルーム (room) のメンバー (member) 一覧を取得する例です。

query {
  viewer {
    # a chat room has many members
    rooms(first: 10) {
      name
      members { name } # room.members による問合せが10回
    } } }

この場合も members { name } を取得するSQLが room の数だけ発行されてしまいます。

Room.readable_by(current_user).limit(10).map {|room|
  # room.members が10回
  {name: room.name, members: room.members.map {|member| {name: member.name} }
}

このような問題の解決方法のひとつとして、graphql.org の Best Practices では複数の問合せをひとつにまとめる Batching を挙げています。これの Ruby での実装としては graphql-batch という gem があります。graphql-batch は特定の DB やライブラリに依存しておらず、問い合わせをする部分も自分で実装できるため、比較的導入しやすい gem です。さっそく使ってみましょう。

graphql-batch を使ってみる

graphql-batch を使うと「ひとつひとつの問合せをいったん Promise として保留にしておき、あとでまとめて問合せ」られるようになります。この「まとめて問合せ」を行なう処理は Loader というかたちでアプリケーション側に実装します。

class RecordLoader < GraphQL::Batch::Loader
  def initialize(model_class)
    @model_class = model_class
  end

  def perform(ids)
    @model_class.where(id: ids).each do |record|
      fulfill record.id, record
    end

    ids.each do |id|
      fulfill id, nil unless fulfilled?(id)
    end
  end
end

RecordLoader#perform(ids) が実際に問合せを行なう部分です。これを使って、message が投稿された room (message.room) を取得するための resolver を次のように書けます。

MessageType = GraphQL::ObjectType.define do
  field :body, !String
  field :room, !RoomType do
    resolve -> (message, args, ctx) {
      # message.room の代わりに:
      RecordLoader.for(Room).load(message.room_id) # => a Promise
    }
  end
end

RecordLoader.for(Room).load(…) は実際の関連 (room) ではなく Promise を返します。ここではいったん Promise を返しておき、必要になった時点でまとめて問合せて fulfill するというわけです。

RecordLoader#for は引数ごとに RecordLoader インスタンスをひとつだけ作って返します。例えば RecordLoader.for(Room)RecordLoader.for(Message) では違う Loader オブジェクトが返りますが、同じ引数で2回呼んだときは前回と同じものが返ってきます。RecordLoader#new の引数は、問合せをどういった単位でまとめたいかによって決まると言えるでしょう。

RecordLoader#load には、ロードする対象を一意に特定するためのキーを渡します。この例では Active Record のプライマリキー (id) を渡しています。ここで渡した id は各 Promise を解決するタイミングで RecordLoader#perform に ids としてまとめて渡されます。このようにして、元々は複数の message.room だったものを Room.where(id: ids) というひとつの問合せにできます。

Loader の応用例

Loader の実装としては、上記の RecordLoader の他に ActiveRecord::Associations::Preloader と組み合わせるというやり方も考えられます。これによって Active Record の eager loading の仕組みを利用できます。

class HasManyAssociationLoader < GraphQL::Batch::Loader
  def initialize(_model_class, association)
    @association = association
  end

  def perform(owners)
    ActiveRecord::Associations::Preloader.new.preload owners, @association

    owners.each do |owner|
      fulfill owner, owner.public_send(@association).to_a
    end
  end
end

この Loader を has_many な関連である room.members の読み込みに使うことで、複数の room.members をひとつの Preload に置き換えられます。

RoomType = GraphQL::ObjectType.define do
  field :name, !String
  field :members, [!UserType] do
    resolve -> (room, args, ctx) {
      # room.members の代わりに:
      HasManyAssociationLoader.for(Room, :members).load(room) # => a Promise
    }
  end
end

注意点として、この方法は関連を一気に読み込んでしまうため、数の多い has many な関連の一部だけがほしいような場合には不要なレコードを大量に読み込んでしまう可能性があります。

また、冒頭でも述べましたが graphql-batch 自体は特定の DB やライブラリに依存していないので Active Record 以外にも応用できます。例えば、Rails のキャッシュを fetch ではなく fetch_multi でまとめて取得する Loader をつくり、バックエンドとのラウンドトリップを抑えるという使い方もできるでしょう。

おわりに

主に graphql-batch を使ってバックエンドへの問合せを減らす方法について、基本的なものではありますが、いくつか例を紹介しました。Ruby で GraphQL を触りはじめた人たちの参考になれば幸いです。

今回のような N+1 Query を解決する際のよくあるやり方としては、Rails アプリであれば Active Record の includeseager_load などを用いた、いわゆる Eager Loading を用いることだと思います。同じことを GraphQL で行なう gem としては graphql-query-resolver があります。この gem は ActiveRecord::Associations::Preloader を使って、クエリに含まれる関連をまとめて問合せてくれるようです。ただ、試しに少し使ってみたところ、数の多い has_many な関連を扱う場合やクエリのカスタマイズをしたい場合にはすこし工夫が必要そうな印象でした。もしも新たな情報が得られたら、またどこかで共有できればと思います。

改訂2版 パーフェクトRubyが出版されました

こんにちは。takkanm です。

本日 2017/05/17 は、弊社メンバーが関わっている書籍パーフェクト Ruby の改訂2版の発売日です。

パーフェクト Ruby は、Ruby に関する内容を言語仕様から、メジャーなライブラリまでを網羅することを目的とされた書籍です。 弊社からは、私と hibariya が執筆に携わっています。

初版は 2013 年に発売されたので、今回は 4 年ぶりの改定となります。 改定内容としては、初版時にターゲットとした Ruby のバージョンである 2.0 から、昨年末にリリースされた 2.4 までの差分をアップデートしました。対象バージョンのアップデートにおいては追加されたメソッドが追加されているのはもちろん、初版から大きく仕様の変わった refinements についての内容を大きくリライトしました。 さらに、初版が発売後に対象を Rails に絞ったパーフェクト Rails が出版されたということもあり、Web 関連の章が削られ、代わりに test-unit を使ったテストの章が追加しています。 このように追加要素も多いので、初版を持っている方にもオススメです。

紙の本は、Amazon やお近くの書店でお求めいただけると思いますし、GihyoDigitalPublishing では PDF でもお買い求めいただけます。

みなさんが Ruby でプログラムを書く際の良きお供になれば幸いです。

併せて読みたい