upinetree's memo

Web系技術の話題や日常について。

できる! mathn 脱却

この記事は STORES.jp Advent Calendar 2019 の 6 日目の記事です。

STORES.jp のバックエンド基盤チームでは、絶賛 Ruby のバージョンアップを進行中です。Ruby のバージョンアップはコード全体に影響を及ぼすため毎回一大イベントなのですが、本記事ではその中でも特に過酷だった事例を紹介します。それは「いつの間にか依存していた mathn を取り除かないと Ruby のバージョンを上げられない」というものでした。

mathn とは

Ruby 2.4 まで標準添付されていたライブラリで、数値ライブラリの挙動をグローバルに変更するものです。以下のように mathn の require の有無によってグローバルに計算結果が変わります。

1/2                #=> 0
2 * Rational(1,2)  #=> Rational(1,1)

require 'mathn'
1/2                #=> Rational(1,2)
2 * Rational(1,2)  #=> 1 (Fixnum)

Ruby 2.2 では Deprecated warning が表示されるようになり、Ruby 2.5 では外部ライブラリとして切り出されました。そのため完全なドキュメントは Ruby 2.1 のものが最後となっています。

https://docs.ruby-lang.org/ja/2.1.0/library/mathn.html

上記ドキュメントから引用すると、 mathn を require することにより以下の挙動が変化するようです。なかなかにダイナミックなモジュールですね。

  • 整数の除算が割り切れない場合、 Rational オブジェクトを返すようになります。
  • 複素数有理数の演算結果が実数や整数に収まる場合、 Float オブジェクトや Integer オブジェクトを返します。
  • Math モジュールの数学関数の定義域と終域を、実数のみから複素数へと拡大します。

いつの間にか mathn に依存していた

mathn は数値計算を行うようなスクリプトなど、使い所によっては便利なモジュールです。ただ、Ruby の標準の動作を上書きし、あらゆる計算結果に影響を及ぼすので、混乱を招く面があります。そのため、Web アプリケーションやライブラリで読み込むようなことはオススメできません。

しかし、思いもよらぬことは起こるものです。 stylish という gem が require 'mathn' していて、それが Rails アプリケーションから読み込まれていたのです。つまり、この Rails アプリケーションでは、気付かぬうちに計算の挙動がグローバルに上書きされてしまっていました。その事実に気づいたのは stylish が入ってから数年後で、その頃にはすでに mathn を前提とした計算がコードベースに深く浸透していたのでした。

基本的には誤差が無くなる方向に作用するものなので、混乱を招く以外に実害はありませんでした。また、広範囲に影響していることから、 mathn を取り除くコストとリスクを踏まえて対応を先送りしていました。しかし、Ruby 2.5 にアップデートするときに、この問題が顕在化したのです。

Ruby 2.5 では、前述の通り mathn は外部ライブラリとして切り出されています。そのためアップデートにあたっては、ひとまず Gemfile に(外部ライブラリとして切り出された) mathn を記述して回避しようと考えていました。しかし実際に Ruby 2.5 に上げてみると、 mathn が原因で segfault するケースがあることがわかりました。

$ ruby -r mathn 'Time.at(1.1).to_s'
-e:1: [BUG] Segmentation fault at 0x0000080000000001
...

mathn はすでに deprecated なライブラリで、修正は期待できません。つまり、Ruby 2.5 にアップデートするためには mathn から脱却しなければならないということです。アップデートしないという選択肢はもちろんありませんよね。

入り込んだ mathn を取り除くためにやったこと

mathn 前提の計算はコードベースに無数に存在し、影響範囲は検討がつきません。それでも mathn を取り除かないと Ruby をアップデートできないので、なんとか工夫を考えました。

mathn による動作変更の理解を深める

まずは mathn が何をしているのかをよく知る必要があるので、コードリーディングをしました。 Ruby 部分はシンプルな実装なので難なく把握できました。

一方で C 拡張部分はなかなか複雑で、ドキュメントに書いてあった動作と照らし合わせながら、仕組みと影響範囲を理解することに努めました。 canonicalization 変数の作用を起点に見て回っていた記憶があります。たとえば ここ とか ここ とかから掘っていきました。

結果として以下のメソッドに影響がありそうだということがわかりました(網羅できてはいないが、あたりを付けるところまでをゴールとした)。

  • Xxx#to_r
  • Date#-
  • Date#ajd
  • Date#amjd
  • Date#marshal_load
  • Date#day_fraction
  • DateTime#-

影響調査範囲を絞り込む

mathn の影響箇所を人力で漏れなく洗い出すのは現実的ではありません。アプリケーションコードだけではなく、依存するライブラリ内部の計算結果にも影響するので、そこまで考慮するのはより一層難しくなります。

なので、ある程度網羅性を緩めた条件を設定することにしました。以下のように、アプリケーションの「出口」のみに焦点を当てるような仮定を設けました。

  • ライブラリ内部では通常は mathn がないことが前提になっているので、精度を求める場面では明示的に考慮するはず
  • Rational/Complex の自動丸めがなくなることは精度を低下させるような影響はないので、処理の途中の計算では問題ない
  • 出口であるリクエストやレスポンスの生成で顕在化した差異をやっつければよい。例えば、自動丸めされなくなり Rational が String に変換されて 3/1  のようになると困る

以上を前提とすると、次の方針が立てられます。

  • Rational を返すメソッド呼び出しを洗い出し、アプリケーションの出口に影響するかを判断する
  • メソッド呼び出しの検知は TracePoint の  returnc_return  イベントを掴む
  • Rational が Integer になって困るケースを検知するため、 mathn 削除前に TracePoint を仕込んで CI で検証する
  • Integer に丸められていたのが Rational になって困るケースを検知するため、 mathn 削除後に TracePoint を仕込んで CI で検証する

TracePoint で Rational の存在を検知し、影響を判断する

以下のようなモジュール(厳密には使用したものとは違います)を用意して、アプリケーションコード中の Rational が返ってくるメソッド呼び出しを検知しました。

module RationalDetection
  class << self
    def enable
      return if @trace_point
      trace_point = create_trace
      trace_point.enable
      @trace_point = trace_point
      @oneshot_detections ||= {}
    end

    def disable
      return unless @trace_point
      @trace_point.disable
      @trace_point = nil
    end

    def save_oneshot_detections(version: nil)
      dir = Rails.root.join('tmp/artifacts')
      filename = dir.join(["rational_callers_#{mathn_enabled? ? 'with' : 'without'}_mathn", version].join('_') + '.txt')
      FileUtils.mkdir_p(dir)
      File.open(filename, 'w') { |f| f.puts(@oneshot_detections.keys) }
    end

    private

    def called_from_app?(path)
      ['app', 'lib', 'config'].any? { |dir| path.match?(Rails.root.join(dir).to_s) }
    end

    def rational_instance?(object)
      Kernel.instance_method(:class).bind(object).call == Rational
    end

    def mathn_enabled?
      $LOADED_FEATURES.grep(/mathn\.rb/).present?
    end

    def create_trace
      TracePoint.new(:return, :c_return) do |tp|
        next unless rational_instance?(tp.return_value)

        caller_index = tp.event == :c_return ? 0 : 1
        caller_path = caller[caller_index].rpartition(/:/).first
        next unless called_from_app?(caller_path)

        @oneshot_detections[caller_path] ||= true
      end
    end
  end
end
  • called_from_app? メソッドの呼び出しでは、ライブラリの内部での mathn の影響を前述の仮定のもとで無視しています
  • 一度だけ呼ばれていることを確認できれば良いので、 @oneshot_detections のハッシュでフラグ管理しています。そして CI の Artifact としてテスト終了後に書き出します
  • 戻り値が Rational かどうかの判定のために is_a? を使わずにわざわざ rational_instance? という怪しげなメソッドを定義しています。これは、BasicObject を継承していて method_missing が定義されているクラスは、 is_a? を呼び出した際に method_missing が呼ばれてしまい、その実装により誤検知もしくは例外を発生してしまうケースがあったためです。また、 defined? による判定も true になってしまうようでした( Ruby 2.7-preview1 で確認したときは false になっていたので、どこかで修正されたのかな)

このモジュールを RSpec の実行時に呼び出すようにして、

config.around(:example) do |example|
  RationalDetection.enable
  example.run
  RationalDetection.disable
end

config.after(:suite) do
  RationalDetection.save_oneshot_detections(version: Time.current.to_i.to_s)
end

CircleCI で mathn あり、なしの両方の条件で実行し、結果を Artifact として得ました。そして一つ一つ出口への影響有無を判断し、必要な修正を行いました。

TracePoint で検知できない範囲への対応

検知可能なのはテストで通る範囲のみとなるので、それ以外の部分についても影響がないことをできる限り確認したいところです。かといって TracePoint を本番で運用するのはパフォーマンスやリスク面で難しいものがあります。

そのため、事前の mathn のコードリーディングや TracePoint で検知した結果得られたパターンで再度 grep して横展開しました。

TracePoint 以外の選択肢?

  • AST だと評価結果が得られないので Rational を返すタイミングがわからない
  • ISeq は AST をコンパイルした命令列なので、やはりこれも評価結果を得られるわけじゃない

というわけで、戻り値を検出するという目的のためには TracePoint で実際の評価結果を知る必要がありそうでした(後学のため、他の方法があれば教えてもらえると助かります)。

まとめ

そんなこんなで mathn の脱却に成功し、 Ruby 2.5 へのアップデートも無事に完了したのでした! 🎊

あまり同じ事例に遭遇することはないとは思いますが、この事例から得られる教訓としてはこのあたりでしょうか。

  • gem を入れるときは、require したらどうなるかをしっかり確認する
    • 他の例として、過去の Whois gem がある。この gem は Rails の core_ext 部分をごっそりコピーしてきて自分で持っていたので、 Rails を新しくしても古いままのコードで動くことになっていた
    • https://github.com/weppos/whois/pull/317
    • (メンテナンスされていれば)バージョンを上げることで致命的な問題は解消することが多いので、そういった意味でも新しいバージョンに追従しておくのは大事
  • ライブラリを作るときはその影響範囲をできるだけ閉じておく。副作用がある場合、ドキュメントにわかりやすく記載する
  • テストをしっかり書いてあると救われる(なかったらと考えるとゾッとする 😂 )

新婚旅行でフロリダのディズニーワールドに行ってきた

2019/9/11 ~ 9/18 の6泊8日で、アメリカのフロリダ州ウォルト・ディズニー・ワールドWDW)に行ってきた。

アメリカ、初WDWだったこともあり、記憶が新鮮なうちに感じたこと思ったことをまとめておく。

…と書き始めた頃は思っていたが、ダラダラしていたらすでに1ヶ月近く経過してしまった 🙈

まだまだ書けることはあると思うが、一旦ここまでにして、思い出したら都度追記していこうと思う。

旅程

移動は羽田発トロント経由オーランド着(帰りはその逆)。カナダを経由するのでETAの申請をしたのが多少面倒だった(システム障害のせいか、何度申請しても最初からやり直しになってつらかった)。

深夜に移動したり、空港での待ち時間が多いスケジュールだった。転職というイベントもあって準備時間の節約のためにHISに依頼したが、正直この判断は間違いだった(後述する)。

とまあ色々大変だった面はあれど、旅行自体はめっちゃ楽しかった。現地の人に毎年来てと言われたが、お金と時間さえ許せば本当に毎年行きたいと思えるほどだった。

アメリカ(フロリダ)について感じたこと

あくまでフロリダ、ディズニーという母集団に対する個人的な印象。感じたことをつれづれと書き残しておく。

  • バリアフリー先進国
    • 設備はもちろんのこと、実際にそれが頻繁に利用されている。車椅子の方が多く外出していて、自然に受け入れられている
  • 大人は見た目イカツイので一見怖いけど、なんだかんだ親切にしてくれる
    • 関わった人みんな良い人だった
    • 肥満の人が思った以上に多い。男性は肥満かマッチョかといった印象…
    • 子供が天使
  • 食事が口に合わなかった
    • 基本的に塩気が強く旨味が少ない
    • デザートで参ったのはクリーム。ジャリジャリして砂糖感が強く、科学的な風味がする
    • 高いレストランでは普通に美味しかったが、外国人向けに調整されているのかも?
  • 水が合わなかった
    • 鉱物の影響か、独特の臭さがある
    • 手荒れがひどくて痛くなり、常に保湿クリーム塗ってた
    • シャワーで髪もギシギシ
  • 日差しが強い
    • サングラスを常につけていた
    • 日焼け止めのANESSAがめちゃくちゃ効いてほぼダメージなし。すごい
  • 雨がよく降る
    • いわゆるスコールで、すぐ止む
    • 現地の人は慣れているのか雨を全く気にしない。すごい
  • コミュニケーションの違い
    • 「How are you (doing)」 ってほぼ最初に聞かれるに慣れずに毎回怯む。とりあえずキョドりつつ good とか答えてたけど、ネイティブはどういう返しをするんだろ
    • とにかく褒める。肯定する。子供は自立させて何でもやらせる。周囲も含めて寛容さがあるのかもしれない
    • ちょっとしたことでも声をよくかけてコミュニケーションする。個人的な経験上、日本ではお互い黙って勝手にピリピリする場面がよくあるなあと思っているが、一言言えば済むことも多いので見習おうと思った
    • (蛇足)それぞれの文化圏ではそれぞれの集合体が生き残るために築いたコンテキストがあり、良いところも悪いところもある。なるだけ良いと思ったところを取り入れていきたい。長年生きてきた上でのアンラーニングは難しいが、定期的に他の文化圏に行くことで自分のコンテキストを認識する機会を作るのは良いことだなと思った
  • エアコン冷やしすぎ。上着がないとつらい場面もあった
  • レストランでのカードでの支払い手順が面倒(チップのせい)
    • あらかじめ調べておくとスムーズ
  • シャワーのお湯の出し方は服を脱ぐ前に確認すべし。初見ではまじでわからん仕組みのものがあるので、裸で試行錯誤するのはつらすぎる。なお、高いホテルだと分かりやすい仕組みのシャワーが付いてた

ディズニーワールド

  • 規模がおかしい
    • 東京ディズニーランドが5つくらいある感じ。ホテルやその他施設を含めれば、ひとつの都市(むしろウォルト王国)と言っても良いくらい
    • ホテルの数も多く、それぞれめちゃ広い。クオリティは課金次第だが、外装や庭、プールなどのこだわりは廉価帯のホテルでもかなり高い
    • 毎日そこかしこで花火が上がっている。消費量やばそう
    • ほぼ物販だけのパーク?がある (Springs)。だいたいここで揃う。グッズの種類に驚愕。グッズはマイナーなキャラのものもあるのでマイナーキャラ好きの妻もニッコリ。服も揃っていて、なかでもTシャツの種類がすごい
  • とにかくUXがよい
    • リアル、ウェブ、アプリの連携がスムーズ。ウェブで計画・予約し、アプリを見て行動し、リアルで楽しみ、結果がアプリにフィードバックされる。アプリ取得必須
    • マジックバンド考えたひと天才
      • パークへの入場、ファストパスの使用、決済、ホテルへのチェックイン、ルームキー、フォトパスの本人確認などがマジックバンド1つあればできる
      • 1段上のセキュリティが求められる場面では、ちゃんと指紋と合わせて二要素認証される
      • カスタマイズ(課金)要素もあり、自分の好きなデザイン、使用感にできる
      • 好きなデザインにしたければ、事前にウェブで指定しておく。日替わりでデザインが変わるのでガチャっぽい
    • フォトパスすばらしい
      • パーク内外にカメラマンがいて、写真を撮ってくれるシステム。思っていた以上の数のフォトパススポットがあって、行く先々で撮ってもらった。枚数でいえば200枚ほど
      • マジックバンドで本人確認して、撮ってもらった写真はアカウントに紐付けられたクラウドストレージにアップされる。そしてアプリですぐ確認できる(タイムラグが発生する場合もあるが)
      • 特定のポーズに対応した効果やアニメーションが付与される場合もあってたのしい
      • 課金要素ではあるが、必須。事前に予約すると安くなる
    • ホテルは自動チェックアウト。時間になるとマジックバンド購入分のレシートがメールで届く
    • セルフのドリンクサーバー用で、一度買ったら何度でもリフィル可能なマグがあって便利。RFIDで購入済みかチェックしているようだった。RFIDが反応しなくなることがあって、レジの人に相談したら登録し直してくれて復活した
  • 園内の様子
    • 入場の際の荷物検査が厳重で隅々まで見られる。検査員はだいたいイカツイけど、気さくに話しかけてきてくれる
    • 家族連れが多い。3代で来ていたりする。日本人はハネムーンの人をよく見かけた
    • アバターのアトラクションめちゃ楽しかった。あとアナ雪のレリゴーを合唱するショーはテンション爆あげの方たちの歓声がたのしかった
    • ことあるごとに歓声が上がる。テンション上がり切るとショーの前にウェーブが起こったりする(たのしい)
    • スターウォーズエリアの作り込みがすごいので、ファンはぜひ。ショーも頻繁で、ベイダー卿が子供たちにフォースの使い方を教えてたりする
    • ハロウィンイベント(要課金)の日本にはない盛り上がり。DJがアゲアゲの曲流してる中みんな酒飲みながらキャラクターと一緒に踊ってたりする
    • イベントに応じたバッジがもらえる。はじめて行くとか、誕生日とか、ハネムーンとか、お祝い事があるなら、キャストに言うと良い
  • キャスト(従業員)の多様性が印象的だった
    • 老若男女、多人種なのはもちろん、車椅子で働いている方もいた
    • 日本からの大学生インターンを多数受け入れている模様。半年くらい滞在するんですよ~と話を聞いて羨ましいねと話していた。大変そうではあるが、英語でのコミュニケーションの練習にもなってよさそう
  • バス、モノレール、船、(+新しくできるSkyline)と、移動手段が豊富
  • 滞在期間中のホテルの移動には luggedge transportation が便利(チップ発生)
  • グランドフロリディアン(ホテル)にはマジックキングダムの花火を見るための開けたスペースがあった。スピーカーも設置されてて、花火のショーの音楽も聴けた。富裕層のための特等席という感じだった…
  • お土産に向いた個包装でたくさん入ってるお菓子があまりない。そして日本人の口には合わなそう…結局お菓子は経由地のカナダで買った

振り返り

持っていって良かったもの

  • GoPro持って行ってとてもよかった。旅の雰囲気とか、夫婦で実況する感じで残せた。購入も検討している。レンティオでレンタルしたが、注文から返却までストレスフリーだった。すばらしや
    • GoProの長いマウントはパーク内への持ち込み時に注意された(畳んでいるならいいけど展開すると没収されるよ、みたいな話)ので、短い棒で行くのが良い
    • オリジナルの動画は結構サイズ大きいので、S3 Glacier Deep Archive で保管することにした。参照しなければ 1 GB あたり月額 0.00099 USD で済む。50 GB なら月 5 円くらい
  • 休息時間という湿布が良くきいた。普通の湿布だと妻は肌に合わないのだが、これは問題なし。持ってく量が少なすぎたので今度遠出するときは増やしていきたい
  • 蒸気でホットアイマスクという製品がよかった。袋開けるだけなので機内でも使えてホッとできる。というか目を駆使する仕事なので普段から使えるわ
  • のどぬ~るぬれマスク。機内は乾燥するので、これつけておくと快適に寝られる
  • ユンケル黄帝顆粒。毎日一日中歩きまわるので、体力回復が課題。顆粒はかさばらなくてよい。持ってく数が少なかったので今度は増やしてみたい
  • 小さな包装の除菌ティッシュ。なんだかんだ使うシーンが多い
  • 酔止め。アトラクションは苦手だけど、せっかくなので乗りたいという人におすすめ(妻がそうだった)
  • 虫除け。ディズニーワールドは自然が豊富で水場が多いので、必須といえる
  • サングラス。快適に行動するために必須。せっかくなのでグッズを買っても良い
  • 日焼け止めのANESSA。マジで効く
  • ビタミンCのサプリメント。シャワーで髪がギシギシになる対策として、サーファーの美容師に妻が教えてもらったらしい。直接カプセルをあけて塗り込む。根拠はよくわからないけど、髪の調子は結構よかったようだ
  • レインポンチョ。スコール対策。行動時に荷物になるデメリットはあるので、濡れる覚悟ができていれば不要(でも風邪をひいたら悔やみきれないので、今回は万全の体制で臨んだ)。夏なら半袖短パンで水着を下に着ていれば良さそうではある。それでもエアコンの冷え対策は必要か
  • 防水かばん。同上の理由。ノーティアムのこれが動きやすくて良かった
  • 洗剤。ホテル内にコインランドリーがあり、そこで使える(洗剤も買えるが、馴染みのものを買っていくと良い)。なお、コインランドリーはマジックバンドが使えず、クレカ決済になるので注意

やっておいてよかったこと

だいたい妻がやってくれたものだが

  • ファストパス取得
    • 結構前からできるので、早めの行動がよい。人気のものは割とすぐに埋まってしまう
  • レストラン予約(キャラクターダイニングとか)
    • これも人気のものはすぐに埋まる
  • 以上のスケジュール表、やりたいこと・行きたい場所リスト作成
    • 妻が旅のしおりを作ってくれて、スケジュールやお土産リスト、持ち物などの確認がしやすかった。事前にワクワクする効果もあり
  • フォトパスの事前予約(安くなる)
  • ガイドブックの熟読と行動順の整理
  • マジックバンドガチャ
    • 悩んだ挙げ句最終的には単色にしてしまった
    • 選ぶのはたのしかった

HISを利用して後悔したこと

  • 6泊8日なので丸6日は行動できます、という説明のプランだった
  • 妻は海外旅行初めてだし、時差とかきついので余裕のある旅程にしてとリクエストした
  • しかし出発1ヶ月前に確定した旅程は遅く出発し、早く帰るというもの。睡眠時間を考慮すると4.5日しか行動できない。ホテルやチケットも6日分のものになっているのにその価値を消費しきれなかった
  • どうやら、契約したプランの可変時間帯のギリギリを提示されたらしい。なのでプラン自体は契約通り。とはいえその説明はなかったし、事前に余裕を持って行動したいと伝えているのに他のプランを提示しないというのは、旅行代理店に期待する価値を大きく満たせていないと感じた
  • 有料での延長も価格交渉も受け付けられないとの支店長判断にがっかり
  • それ以外にも担当者が催促するまで連絡よこさないとか、請求書に誤りがあるとか、名前を何度も間違うとか、色々おかしかった
  • 逆にこれらのやりとりで時間を取られてしまった。WDWに行くというくらいの目的なら複雑な旅程でもないし、大金を払って無駄な時間を費やすくらいなら、最初から全部自分でやればよかった
  • 一方で現地スタッフの存在は心強かった。はじめて行く地ということもあり、色々ガイドしてくれたのがよかった。ただ、他の旅行代理店でもそういうサービスはあるし、直接依頼するということもできるので、それが決定的な価値になるというわけではない
  • 総じて、もう利用することはないな、という結論になった

その他

  • WDW目的なら現金はもっと少なくていい。だいたいマジックバンドでなんとかなる。WDWの外でもクレジットカードだけで大丈夫。チップでまれに現金が必要になる
  • 体力不足、体力の過信、体調管理。疲労によりショーを断念することになった(翌日にリベンジできてよかったが)
  • 英会話の準備不足…全然話せなくなってる。色んなとこで雑談チャンス発生してたのに全然対応できなくて悔しかった。妻は英会話苦手なのに果敢に挑戦しててえらかった。チキンな私には真似できない

まとめ

もともと私自身そこまでディズニーのファンではないのだけど、今でも2日に1回フロリダが恋しくなるくらいに楽しかったのでみんなもっと行くといいと思うよ(長時間の飛行機のつらさと、お金と休暇がなかなか捻出できないという現実が立ちはだかる…)。

あと、密かに目標にしていた「ケンカしない」というのを達成できたので、新婚旅行としては大成功だった。

事前の入念な調査と準備、持ち物の整理をしてくれた妻に感謝である(妻の荷物の多さを小馬鹿にしていたが、結果として助けられたのである。すまんかった)。

転職しました(5年ぶり2回め)

Diff

- 万葉
+ STORES.jp

なんで

  • ずっと受託開発をやってきて、そこそこお客さんに価値を提供できるようになってきた
  • 一方で自分のキャリア上に運用経験がないことがずっと心に引っかかっていて、自分(たち)の製品・サービスに主体的に関わってみたいと思った
  • また、サービスに愛着を持ってなんやかんや試行錯誤したりといったこともしてみたかった
  • というか、そういった経験もなしに受託開発を続けても、心理的・技術的に提供できる価値に限界があると考えた
  • 受託開発ではこのあたりに踏み込むのが難しくて、組織とか権限とか情報とかにおいてたくさんの制約がある。そういう構造があるのは当然というか妥当で、その中でWin-Winになる範囲で踏み込む努力もしたが、自分にはどうしても器用にできず難しかった
  • そんなこんなでゆるゆる1年前くらいから転職を意識していた
  • STORES.jp はエージェントさんに紹介してもらって、細く長くコンタクトをとっていくうちにたのしそうだなーという感覚を持っていった
  • 明るく前向きにやっていくぞという雰囲気で、かといってキラキラでもなく。エンジニアも向上心があって、かといってムキムキマッチョでもなく。といったところが結構合うなと思った
  • みんな STORES.jp というサービスが好きで、自分もサービスに愛着を持っていけるかなという感じがした(そして実際そういう魅力のあるサービスである)
  • 条件面に関しても交渉の中でかなり配慮していただいてありがたい限り

おきもち

やっていくぞーという感じです。

万葉には大変お世話になって、感謝の気持ちが尽きない。 万葉のおかげでWebアプリケーションエンジニアとして一人前になれたし、リーダー業務だったり執筆だったりと、いろいろな経験の機会をいただけた。あと妻にも出会った。 なので、申し訳なさとか、さびしさもある。 しかしここは次のステップに進むと自分で選択したのでがんばろう。

実はSTORES.jpにはちょっと前から不定期にアルバイトで入っていて、正社員としては今日からとなる。 マインドの切り替えとか、情報量の多さへの慣れとかまだまだで、ちょっと疲労もたまりがちなのだけど(風邪引いたり)、まずは体調優先で着実にスタートしていきたい。

直近の心配は、万葉の7時間勤務に慣れきっていて勤務時間ショートしないかなというところ…。

これからも相変わらず Ruby, Rails をメインでやっていくし、各種カンファレンスにも顔を出すのでよろしくおねがいします。 あと、恵比寿に通っているので、近辺の方はゆるっとランチとか飲みとかいきましょー。

例のリスト

http://amzn.asia/0Ly1XAG

Ergo42 Towel を作った

遊舎工房さんの実店舗でキットを購入。meishiを除けば最初の自作キーボードだったので、作りやすそうで、コンパクトだけどある程度キー数があるスプリットキーボードという点で選定。

構成

  • キースイッチ
    • Gateron Silent Brown * 56
  • キーキャップ
    • MDA Big Bang セット

ログ

f:id:upinetree:20190505103522j:plain

ダイオードのはんだ付けが完了したところ。付属のアクリル脚の幅が曲げるのにちょうどよかったので、簡易的なリードベンダーとして利用してみた…が、雑に行ったせいで仕上がりはそんなにきれいではない。

f:id:upinetree:20190506121821j:plain

キースイッチのはんだ付けが終わったところ。ケースの組み立て前にそれぞれのスイッチをテスタで導通確認し、ファームウェア書き込んで動作確認。

f:id:upinetree:20190506235112j:plain

ケースを取り付けてキーキャップを乗せたところ。これで完成!

と思いきや、ここからが長かった。

キーマップ

せっかくなので親指を酷使できる配列にしたいとか、キー数が少ない中で効率的な記号配置をしたいとか、でも慣れるのに時間のかかる配置は避けたいとか、キーマップにはいろいろと悩んだ。

ファームウェアを書き込んで実際に触ってみると、普段のユースケースではつらい場合があることもわかったり、なるほどこれがキーマップ沼かと実感。慣らしつつ少しずつ育てていくのがまたひとつの楽しみなのだろう。

とりあえず今のところは以下の配置にしてみている(すでに上記の写真とは違う)。

f:id:upinetree:20190512221730p:plain

感想

  • 親指を酷使する配列は指の移動が減って小指が快適
  • 慣れるまでが大変そう。格子配列もまだTypoしまくるし、すべてのキーが同じ大きさなので指先の感覚が今までと違う
  • MDAキーキャップだと高さ(とくに最下段)が合わなくてガタガタになる。DSAとかを買い増しかしら…
  • Pro Micro の microUSB 端子がもげやすいと聞いて用意したZrseのマグネット式ケーブルが便利だった。端子部分を余分に用意しておくとファームウェア書き換えのときに差し替えがらくちん
  • 持ち運び用のいい感じの入れ物がほしい

meishi キットで自作キーボードに入門した

自作キーボードが作りたくて遊舎工房さんに行った。 yushakobo.jp

Ergo42 Towelmeishi キット を購入。 買うときにいろいろと教えてくれたり、こちらのふわっとした相談に乗ってくれたりしてありがたかった 🙏

meishi キットは練習用に買ってみた。 ハンダ付けとか10年くらいやってないし、いきなり作り始めるのも危険そうだったので…。

小さなキットでもキーボードに必要な最低限の要素が詰め込まれていて、入門用として最適だった。 案の定つまづくこともあって、作っといてよかったなーと思った。

f:id:upinetree:20190413233859j:plain
完成したmeishi

キースイッチは、左から

色々試せて楽しい。

Pro Micro の MicroUSB 端子はもげやすいという噂を聞いたので、マグネット式のケーブルも買った。

キーマッピングは今のところ何が便利か思い浮かばず、とりあえず Slate で割り当てていたウィンドウ切り替えに対応させてみた。

便利…か?

https://docs.qmk.fm/#/keycodes あたりを見て、 qmk_firmwarekeyboards/meishi/keymaps/default/keymap.c を変更してファームウェアをビルド&書き込み。 お手軽。

さあ次は Ergo 42 Towel を作っていくぞー。

Rails Developer Meetup 2019 に参加してCSSの技術的負債について発表した

発表内容

https://railsdm.github.io/#session-upinetree

CSSの技術的負債との向き合い方」というタイトルで、普段のチーム開発で目をつぶりがちなCSSをテーマに話しました。

プログラマからの視点で、どういう流れでCSSが負債になるのか、その負債に対してどう取り組んで行けるか、などを色々考察してみたという内容です。

質疑応答: https://railsdm.herokuapp.com/issues/118

スライド

日本語版

英語版

動画

(怖くてまだ自分自身で見られていません…)

感想

以下、感想を思いつくままに並べてみます。

全体

  • とても楽しくて濃い2日間だった
  • この規模のイベントを運営されたカルパスさんすごい
  • 動いているDHH氏を見られてよかった。準備もなしに、饒舌に自分の意見をスラスラ言っていたのが印象的だった
  • 発表が終わった後は他のセッションに気が向くまま参加。疲れていたのもあって休憩していた時間も多かった
  • 2日間共おいしいコーヒーが提供されてとてもQOL高かった
  • これからアップされた資料や動画をゆっくり見て行きたい。RubyKaigiもあるのでそれまでには…

登壇

  • ランチでの現場Rails本のトークセッションから続けての登壇。1時間以上スクリーンの前にいることになってしまったので、結構気疲れした。発表終わってからしばらく放心してた
  • B会場は110人入るとのことだったけど、だいたい席が埋まっている感じで、まさかこんなに多くの人の前で話すことになるとはという感じ

良かったところ

  • 緊張はしていたが、話し始めてからはリラックスしていられたと思う
  • ペースを意識しながらやれた
    • スライドの途中にここまで何分でできたら急ぐ、みたいな目安を決めていた。30分ぴったりで終わって我ながらよくやった
  • 良かったという感想が多くてホッとした
    • CSSは専門領域じゃないので、何適当なこと言ってんだみたいな反応ないか怖かった
    • 関心の谷っていうメタファーいいよねといろんな方に言われてうれしい
  • 全体の構成を紙に書いて考えた
    • 30分ともなると箇条書きで考えるのつらそうだったので
    • マインドマップ的なやつとか、色々絵を書いた
  • 英訳をがんばった
    • 必須ではないし、会場に英語話者の方がいらっしゃっていたかは不明だけど、チャレンジしてみた
    • 海外でのチーム開発や職責の事情は違うのかもしれないけど、リーチできるってのは良いことだ

改善できそうなところ

  • 詰め込みこみすぎた
    • ペースを早めにしないと時間が足りなくなってしまった
    • 息継ぎが少なめになってしまって結構苦しかった
  • ブラッシュアップ期間が取れなかった
    • もう少し余裕を持てたら良かった
    • ブラッシュアップしたらシンプルにできて発表時間に余裕を持てたかもしれない
    • 負債自体は悪くないんだよという話も入れたかったなー
  • スライドが文章だらけになってしまった
    • 何を話すか思い出すためでもあって、これもブラッシュアップできなかった影響
  • 英訳にかかる時間を甘く見ていた
    • 結果として途中まで英語という中途半端な形で発表することに…

今後やってみたいこと

  • Stylelint で橋の使われ方のチェック
    • 発表では「橋が巨大になるに連れて使われ方のチェックが大変になる」という話をしたが、そのあたりも自動化できたら良さそう
  • 谷を埋める方法の掘り下げ
    • みんなでがんばっていくぞ的な抽象的な内容で終わってしまった
    • じゃあその分のコストはどうするのとか、やりたくない、やらないほうが価値を発揮できる人にもやらせるのかとか、色々議論したい
  • 他の領域での関心の谷
    • CSSに限らずあると思うので、色々ディスカッションしたい
    • まずは認識することが大事で、そこからチームで踏み出せていけたらなと思う

自分の結婚式用にサーバレスな招待状Webアプリを作った

結婚しました

2018/12/1 (土) に結婚式を行いました。天候に恵まれ、穏やかな晴れの日で式を挙げられて本当に良かったです。私のことなので直前で体調を崩すか怪我をするか天気が崩れるかのどれかはあるんじゃないかと思っていたのですが、何もなく無事に終えることができて安心しました。

我々夫婦のために多くの方々が集まってくれてとても嬉しかったです。遠くからはるばる来てくださった方もいて、本当にありがたい限りです。

よちよち.rb からも電報をいただいてしまってびっくりしました。 curl から始まり | ruby で終わる電報をいただく(そして困惑する司会の方がゲストに促されそれを読み上げる)機会はそうそうないでしょう 😂 お忙しい中、粋な計らいをありがとうございました。

披露宴の内容やアイテムにはかなりこだわって、我々らしいオリジナリティのある結婚式になったと思います。夫婦で演奏したりもしました(私がギター、妻が鍵盤ハーモニカ、ヴィブラフォンマリンバ)し、謝辞にLTしたりもしました。

現場Rails本の執筆と並行しての準備となってしまってかなりきつかったけど、妻に主導してもらってなんとかなりました。本当に感謝。そしてようやく締切に追われない日々が訪れ、ブログを書くこともできるようになりました。

これから夫婦ともどもよろしくお願いいたします。

(というわけで例のリストです)

http://amzn.asia/0Ly1XAG

招待状Webアプリ

結婚式のこだわりのひとつとして、招待状の回答をWebアプリでできるようにしてみました。せっかくなのでその紹介を書いてみようと思います。

なぜ招待状の回答をWebアプリでできるようにしたかというと、従来のはがきでの回答には以下の扱いづらさがあったからです。

  • 「御」を打ち消したりといったマナーがたくさん。ゲストに手間をかけさせたくない
  • 当日の情報を見たいときにすぐ見られない。地図の検索などの一手間が必要
  • 返信用切手の購入や添付が必要
  • 回答の集計が手入力で大変

一方で、はがきには紙の良さもあります。色々とデコったり、文字でメッセージを伝えたいといった需要もありますし、モノとして手元に残るのはうれしい点です。

そこで、今回は以下のような運用にしてみました。

  1. 招待状は紙で送付。ゲストカードと、招待状アプリの案内カードを同封
  2. 招待状アプリの案内カードには、アクセスするためのQRコードと、ログインパスコードを記載
  3. 招待状アプリで回答していただく
  4. こちらが集計スクリプトで回答結果をチェック(毎日のたのしみ)

QRコードの用意やログインパスコードの添付など、物理との接続のための工夫はかなり苦労しました。正直この作業中ははがきのほうが数倍楽だったのではとも思いましたが、苦労した分だけ楽しみつつも総合的に満足できるものができたかなと思っています。

アプリケーションの構成

公開用に個人情報とか抜いたリポジトリを作ってみました。

https://github.com/upinetree/wedat-demo

今回は前々から興味があったサーバーレスSPAでやってみました。AWSを中心に以下のような構成にしました。

  • リソースは S3
  • 回答結果を DynamoDB に保存
  • API Gateway で DynamoDB にアクセス
  • 認証は Cognito
  • ネットワーク周り
    • CloudFront
    • Lambda@Edge (テスト環境のBasic認証用)
    • Route 53
    • Amazon Certificate Manager

なお、これらの構成は Terraform で管理しました(勢いでかなり雑に…)。

今回はSPAということで、フロント周りはReactで組みました。CRAでシュッと作って、その上に以下の色々を乗せた感じです。

  • Redux
  • Redux Form
  • React Router
  • React Transition Group
  • Luxon
  • Styled Components
  • Tailwind CSS
  • AWS Ampify

なお、CRAの Service worker は途中まで使ったり整備したりしたのですが、キャッシュの更新とかの懸念点の解消が公開に間に合わず、泣く泣く外しました…。

作ってからCRAもAmplifyもかなり大きなアップデートが入っていて、追従できていないのも心残りではあります。作って利用してもらうことが最優先だったので、目的は達成できたということで良しとしています。

やってみた感想

Webアプリにしてみて感じたのは

  • 紙面のような限界がないので、長文でコメントくれる人も結構いてうれしかった
  • 結構びっくりしてもらえた。製品かと思わせることに成功
  • 集計がめっちゃ楽。毎日集計結果とメッセージを確認できるのでモチベーションになる
  • ゲストに名前を入力してもらうので、名前の正確な漢字に手書きよりも確実に気付ける

のあたり。やってよかったな〜と思いました。

技術的な感想としては

  • サーバレスSPAめっちゃ低コストで月に多くて100円程度しかかからない。運用もほとんど気にしなくていい(一応トラッキングはしていたが、安定してからは本当に手が離せて助かった)
  • CRAやAmplifyのレールからはずれたいときに大変だった。結局ソースコードを読みに行った
  • Amplifyが提供するReactコンポーネントはカスタマイズがあまりできなくて、上書きしたりしたり、同じような機能を持つコンポーネントを自作したりした
  • Styled Components 最高だ。Tailwind CSS でざっくりマークアップして、まとまりがでてきたらコンポーネント化するというパターンがかっちりきた
  • API Gateway でとても苦労した。Terraformでの管理が一つ一つのリソースに対して記述量が多くて大変だった。マッピングテンプレートのVTL (Velocity Template Luangage) の記述方法でもめっちゃハマる。これでサーバーレスで柔軟なエンドポイントを定義できると考えて、トレードオフとしてはありのようななしのような…?代替手段があればまずそっちを選択すると思う
  • Cognito もちょっとレールからはずれた使い方をするととたんに応用が効かなくて苦労した。次は Auth0 とか Firebase auth とかも使ってみたい
  • (最終的には採用しなかったけど)Service worker は、キャッシュの扱いで苦労した。キャッシュはCDNにあるのかSWにあるのかブラウザにあるのか、どこの設定が効いているのか、というところ。この規模のアプリのSWキャッシュでそんなに苦労に見合うメリットはないと判断した
  • それぞれのサービスやフレームワークを組み合わせたベストプラクティスがなくて、その都度自分で判断しないといけなかったのは大変だったけど楽しかった。普段書いてるRailsは(レールに乗っていれば)だいぶ楽できるなと再確認

技術的な方はその都度アウトプットできたら良かったのですが、執筆という巨大なアウトプットの最中で断念しました。まだ使える知識がありそうだったらこれから出してみようかと思います。