新しいことをやる為の負荷と学習コストと迷子であることの自覚

読みにくい日記です。

一応今の会社はRubyRailsの会社ってことで通ってると思うんだけど、自分はほとんどRails触ったことなかったので、何かと色々やる必要が出てくる。 今はJavaScriptのフロントのタスクがあんまりなくてRailsやった方がいい感じで、じゃあ勉強がてらやるかって突っ込んだらちょっとウゥムって感じになった。

問題

勉強側に振ってしまいすぎたのもあるんだけど、かなり生産性低かった自覚がある。結局1週間やって出せたのがやりかけのPullRequest一件で、しかもwork in progress で残りお願いします… みたいな感じになってしまった。

で、今回新しいことをやるにあたって問題になったのは、次の点だと思った。

  • 新しい登場人物の多さによる認知負荷の高さ
  • パフォーマンス要件の厳しさ
  • 最初からプロダクション前提の品質要求
  • ペアプロしてくれる人の確保

実は今の会社入るまで仕事でサーバーサイドでやったことなくて(前職はサーバーを相手にするゲームクライアントばかりだった)、学生時代使ってたのもsinatraフレームワークやWebSocket前提っていうプロダクションとはちょっと遠い環境だったから、色々と専門外のことをやるなら学ばきゃいけないことは多くなる。

Rubyは自分が使える言語の中で似ているのはpythoncoffeescriptだと思っていて、それは間違ってなかったように思う。 coffeescriptの文法がpythonrubyのあいのこだから、coffeescript - python = rubyの基礎知識みたいな大雑把な知識でRubyを書き始めた。

この一週間で覚える必要があったRailsの上での汎用知識は Grape, MongoMapper, FactoryGirl, RSpec で, 既存のユースケースを真似ればなんとなく動くけど、概念レベルで理解するには結構重い。それに加えて会社の既存コードに対するドメイン知識もついていく必要があった。

前提として、小さい会社だから教育制度もクソもなく、当該ドメインは勝手に勉強してろって感じになる。それはまあいい。研修なんかより自分で勉強するほうが速い。それはともかく、ピンポイントで質問するときは質問できる環境ってのは良いと思う。というわけで色んな人とペアプロ頼みにいった。

で、仕事としては最初から既に動いてるコードベースに手を入れることになるのだけど、それは適当にrails new した習作なんかではまったくなくて、プロダクション運用前提で、いきなり書くのが怖い感じだった。レビューを受けられるとはいえ、基礎知識がない環境でコード書くの辛いので、一旦会社と同じ構成でプレーンなリポジトリを作ってみることにした。すると新たに Unicorn, Resque, Raven, あとデプロイ環境のHerokuの構築とかやんなきゃーな、とカバー範囲が増えていった。まあ無視できるのもあるんだけど良い機会だしと思って一通り動くまで設定ファイルとかを書いてみるも、ちょっと時間かけすぎた気がする。未知の事象に対して見積が難しい。

で、今回自分に割り当てられたタスクはユーザーの活動ログを集計する系のAPIの作成で、普通に書くとタイムアウトする恐れがあった。結局クエリが重いケースでタイムアウトしてunicornにkillされて問題になったので、キャッシュ作って一時間に一回更新みたいな形になった。厳しい。

で、自分の表示したいデータを表現するには、すごく登場人物が多かった。多対多の中間テーブルを何度もまたいでいく必要があった。いやその設計は間違ってないんだけど、あんまりDB使うプログラミング慣れてなかったから、どういうケースで中間テーブルを作るか、どういうケースでモデルにロジックを生やすか、みたいなセンスがなかったから、既存のコード読みながらなんとなく理解する必要があった。そもそもDB設計の基礎知識が足りてないなァといった気分になる。

辛かったこと、Rubyはアクセスしてるプロパティがgetterなのか素の参照なのかわかりにくい点が認知負荷を上げるのに一役買ってるなーと思う。表面上のAPIは簡素になるんだけど内部的に経由するプロセスを想像しないといけなくなる。パフォーマンス要件が厳しい環境だと辛くなる。

で、なんだかんだでとにかくプリントデバッグとpryによるREPLを駆使して目的のデータ構造を表現できたんだけど(これもまた暗黙知的だが、プリントデバッグプログラマとしての基礎知識なのでそれは問題ではない)、それをRSpecでテスト書かなきゃいけない。まあRSpecというかテストの概念は知ってるからどうにかなるだろと思ってたんだけど、いちいちアサーションのフォーマット調べる必要があるからまた負荷がかかる。というかまずDBのテストだからFactoryGirlで表現して、それをdescriberで入れ子に〜みたいにしていくと、この場合実行順序どうなるんだっけ?みたいなのですごい混乱した。

次から気をつけること

  • 勉強すべきをことはある程度枝刈り
    • 細分化すれば無限に深堀りできてしまう
  • 何がわからないかわからない、っていう状態を言語化するには糞コードでもいいから手を動かして見てもらう。
    • 机上論だと(他の言語ならわかるだけに)わかったふりしてしまう
    • お前はわかってない
  • 悩みを一人で抱えない。共有する
    • Pull Requestは早めに出す

斧投げられる側になると投げてほしい斧がわかる

グランブルーファンタジーのコードをちょっと読んでみた

なんかすごい無茶してますね。 HTML5で普通に読めるので、適当に読んでみた。都合が悪ければ言ってください > Cygamesさん

大雑把にコールしてるライブラリは "jquery","underscore","backbone","easeljs","tweenjs","soundjs","movieclip","preloadjs","loadmanager","pex","typist", "flexslider","finger","socketio","subroute","uaparser"

require.js

全体的にrequire.jsに強く依存している。require.jsは r.js使ってまとめてminifyできるんだけど、今回はそれをしていなくて、uglifyか何かで難読化されているだけ。なんだけど、圧縮できない文字列ベースで依存関係を表現しているため、外部から非常に読みやすい("自分には"読みやすいだけかもしれない)

例えばこんなコードがみえる。

define('model/pagination',["backbone","underscore","model/data"],function(a,b,c){var d=c.extend({urlRoot:function(){...

ディレクトリ構成とか想像できてニヤニヤできる。

画面構成

画面構成としては、全面を巨大なCanvasが覆ってて、各種エフェクトはcanvasの上に描画される。そのCanvasの上にpositon:absoluteの座標系で置いた透明なdivが散らばっていて、当たり判定を作っている。その下は普通のマークアップされたHTMLがあるのだけど、タッチイベントをリッスンしてはいない模様。これは複雑なマークアップをするとDOMのサイズを計算してタッチベントが発火する負荷がかかるから、見た目のマークアップとは別に透明なdivが用意されたものだと思われる。

アニメーションはCreateJS

アニメーションはCreateJSのeasel.jsとtween.jsとmovieclip.js。アセットはおそらくToolkit for CreatejsでAdobe CSから生成されているのではないか。~stageというdivが大量にあってpreloaderから読み込まれているのだと思う。

Flash to HTML5 | Learn more about the CreateJS toolkit

UIは素のBackbone

UI部分はHTMLとBackboneで構成されている。普通のextendスタイル。テンプレートはDOMにscriptタグで埋まっており、underscore.jsの_.templateのようにみえる。通信はどうもWebSocketと普通のAJAXのハイブリット。たぶん戦闘画面とかでwebsocket使ってるようにみえる。(サーバーサイドのスケールどうしてるんだろう)

pure js

minifyされた結果を見る限り、altjsを使っている形跡はない。coffeeだと前方にvar宣言が固まるし、coffeeやtypescriptのクラス記法ならsuperの記法が歪になる。