JSの開発環境を整えたいけどよく分からない
やりたいこと
- EventEmitterを使いたい
- どうせJS書くならES2015でクラス構文やアロー関数使いたい
ふんわりした認識
- NodeJSのモジュールを使うにはBrowserifyなるものを使う
- ES2015の構文を使うにはTypeScriptかBabelを使う
- 上記の変換工程を自動化するためにgulpなるものを使う
現状
- npmのオプションってそれぞれ何やってるのこれ
- -gはグローバルというのは分かったけど、-Dとか--save-devとか…
- gulpfile.jsの書き方分かんない
- browserify使うのに何でこんなに色々書くの
- トランスパイルの工程はどこに書けばいいの
- babelifyって何、babel-cliとか色々あるのと何が違うの
- 何かクラス構文が変換されない
結論
よくわからない。
問題解決ツール自体が問題なのだ
グローバル状態をstatic APIで触りたくない
まとめ
依存してるグローバル状態はDIで表したい。
グローバル状態を触るstatic API
業務でPlayを使ってるんだけど、 プロジェクト中でフラッシュスコープを扱う際には、 staticメソッド詰め込んだ自作ラッパを使ってる。
これ、最初見たときグローバルな状態を操作してるAPIだって分からなかったし、 今でも他のチームメンバーの書いたソースを読む時は隅から隅まで注意して読まないと、privateメソッドのどっかでグローバル状態が書き換わってたりするのに気付かなかったりする。
public SomeClass someMethod() { ... otherMethod(); ... } private void otherMethod() { ... StaticApi.someApi(); // ここでglobal stateが書き換わる ... }
グローバル状態に依存…依存と言えば
static APIが呼ばれてるかどうかなんて基本的にメソッドの定義を読みに行かないと分からないし (grepしたり呼び出し階層を調べたりするのも調べる手間が掛かるという点で同義)、 メソッドを一目見ただけで何のグローバル状態に依存してるか分かれば楽なのに…と思った所で、思い至る。
あ、これDIやん。
メソッド引数にAPIオブジェクト渡すなり、 アノテーション付けてコンテナにDI任せるなり、 方法は何でもいいけど依存性を明記した方が圧倒的に分かりやすい。
public SomeClass someMethod(DynamicApi api) { ... otherMethod(api); ... } private void otherMethod(DynamicApi api) { ... api.someApi(); ... }
Static APIの非推奨化
で、実際Play公式も同じようにstatic APIを非推奨にして、 DIを使った同機能のAPIを使うように推奨してたりする。
既存プロジェクトをPlay 2.5に移行しようとした時にたっぷりと非推奨警告が出て焦ったり、 「何でこれ置き換える必要あるんだよこれ」とか思ったりしたけど、 要するにこういうことなんだと理解した。
グローバル状態は無くしたいし、グローバル状態を変な所で操作されたくないってことですね。
JavaでHTMLをパースしたい
5分で調べたメモ書きシリーズ(続くかは知らない)
動機
人力テストでExcel方眼紙にスクショ貼り付けるの疲れた。 コントローラの単体テストをコード書いてやりたい。
-> 出力されるビューをパースして含まれる値とか調べたい。
JavaのHTMLパーサライブラリ
ググったらこの辺の記事がヒット。 今回はとりあえずJsoupを使ってみる。
Jsoup
// URLに接続してHTMLドキュメントを取得できる Document doc1 = Jsoup.connect("http://www.google.co.jp").get(); // あるいはStringやファイルをパースできる Document doc2 = Jsoup.parse("<!doctype HTML><html><body><div id=\"hoge\" class=\"fuga\">Hello!</div></body></html>"); // DOM操作が使える Element elm = doc2.getElementById("hoge"); // CSSセレクタも使える Elements elms = doc2.select("#hoge"); // テキストを取得したり System.out.println(elm.text()); // 属性やクラスを含むかを確認できたり System.out.println(elms.hasClass("fuga"));
ところでそもそもコントローラのテストって
普通はどうやって/どういう項目をテストするのが普通なんだろう。 テストコードの書き方を教えてくれる人が周りにいない。
一応技術的なことは上司も話を振ればノッてくれるけど、 皆さん忙しくてコーディング改善とかまで手が回ってないから…
アクション合成
前回の記事ではラムダ式使った共通処理の記述をやったけど、 Playの公式ドキュメント読んでたらフツーに アクション合成 なるものがありましたね。
この機能をいじってみたので使い方メモを残す。
他にもGlobalオブジェクトを作ることで全アクション共通の処理が書けるけど、 特定ページだけ認証したりとかやるならアクション合成を使う。
Actionクラス
合成したいアクションはplay.mvc.Action
public class CommonAction extends Action.Simple { @Override public Promise<Result> call(Context ctx) throws Throwable { someOperation(); return delegate.call(ctx); } }
Http.Context型の引数ctxからはリクエストに関する情報が取れたり、 ctx.argsにマッピングを追加して後続のアクションに情報を伝えたりできる。
合成元のアクションを実行するにはdelegate.call(ctx)を呼び出す。
Withアノテーションによるアクション合成
一番基本的な合成方法。
@With(CommonAction) public Result index() { return ok("Ok"); }
これでsomeOperation()が実行された後にOKレスポンスが返る。
自作アノテーションによるアクション合成
Withアノテーションは複数個書けない。
@With(HogeAction) @With(FugaAction) /* NG */ public Result index() {...}
WithにRepeatableアノテーションがないからなんだけど、 アクションが1個しか合成できないのは不便極まりない。 複数のアクションを合成するには自作アノテーションを使う。
@With(HogeAction) public @interface HogeActionAnnot {} @With(FugaAction) public @interface FugaActionAnnot {} @HogeActionAnnot @FugaActionAnnot public Result index() {...}
パラメータ付きアノテーション
アノテーションのパラメータはconfigurationから取得できる。
@With(PiyoAction) public @interface PiyoActionAnnot { public String value(); } public class PiyoAction extends Action<PiyoActionAnnot> { @Override public Promise<Result> call(Context ctx) throws Throwable { System.out.println(configuration.value()); return delegate.call(ctx); } }
Repeatableアノテーションを使う時の注意
例えば以下のように同じ自作アノテーションを複数個使いたい場合。
@PiyoActionAnnot(value = "piyo") @PiyoActionAnnot(value = "piyopiyo") public Result index() {...}
PiyoActionAnnotにはRepeatableアノテーションを付ける。 引数にはPiyoActionAnnotの配列をパラメータに持つアノテーションを指定する。
@With(PiyoAction) public @interface PiyoActionAnnotHolder { public PiyoActionAnnot[] value(); } @Repeatable(value = PiyoActionAnnotHolder.class) public @interface PiyoActionAnnot { public String value(); }
あれ、Holderの方にWithアノテーション?と思うかもしれないけど、 index()に2個ついてるPiyoActionAnnot、実態はHolder。 なのでPiyoAction側でアノテーションを使う場合も以下のように書く。
public class PiyoAction extends Action<PiyoActionAnnotHolder> { @Override public Promise<Result> call(Context ctx) throws Throwable { for (PiyoActionAnnot annot : configuration.value()) { System.out.println(annot.value()); // PiyoActionAnnotの引数が出力される } return delegate.call(ctx); } }
共通処理とラムダ式
近況
4月から某SI系企業に就職。 3ヶ月間の研修が終わり、7月から配属。
で、OJT…なんだけど次のプロジェクトが始まらないので、 前のプロジェクトのソース読んだり雑用したりしてる。
闇のソースリーディング
で、サーバサイドWebアプリのソースを勉強するという名目で JavaとかJavaScriptとかテキトーに読む日が続いてるんだけど、 まあ重複コードの多いこと。
例えばコントローラの各アクションで共通する処理 (認証情報の確認、チェックボックスの値のセット、等々)が ぜんぶベタ書きされてる。
流石にウンザリしたので、プロジェクトをコピーしてローカルで実行環境作って ソースをいじり回すことにした。
共通処理の抜き出し
匿名クラス
個別処理が関数として渡せるとすれば、 共通処理を行うメソッドはこんな感じに書きたい。
プロジェクトではPlay Framework使ってるのでそれっぽく。
private Result commonAction(/* 個別処理の関数 */func) { commonAction1(); func(); commonAction2(); return ok(); }
ただJavaは関数が第一級オブジェクトじゃないので、 やるならクラス作って渡す必要がある。 匿名クラス使って個別処理も書くとこんな感じ。
private interface Func { void func(Object someArg); } private Result commonAction(Func func) { commonAction1(); func.func(someArg); commonAction2(); return ok(); } public Result individualAction() { Func func = new Func() { public void func(Object someArg) { someOperation(someArg); }; }; return this.commonAction(func); }
ラムダ式
で、ここまで書いて思い当たる。 何かこのインターフェース見たことあるなと。
あ、これConsumerじゃん。 関数型インターフェースじゃん。
じゃあラムダ式使って書き直しましょ。
private Result commonAction(Consumer<Object> consumer) { commonAction1(); consumer.accept(someArg); commonAction2(); return ok(); } public Result individualAction() { return this.commonAction(someArg -> someOperation(someArg)); }
DPやりましょう、是非やりましょう
これは「#音ゲーマー達の発信所 (2枠目) Advent Calendar 2014 - Adventar」9日目の記事です。遅刻ゴメンナサイ。
・概要
皆さんDPやりましょう。
・イントロダクション
初めましての方は初めまして。
カグラ屋(@kagura_miya)と申します。
仙台で細々と音ゲーマーやってます。元々はポップンをメインでやってましたが最近はIIDXのDPに熱を上げてます。
身内に地道にDP布教を続けた結果徐々にDP始める人が増えてきましたが、まだまだ同レベル帯の話ができる人が少ない!というわけで、もっとDPerが増えることを期待してDPの紹介と経験談を語りたいと思います。
そこらの若輩者が図々しいこと語ってますが、もし内容におかしい点等あればご指摘いただければと。
・DPってどんなゲーム?やっぱり難しいんじゃないの?
「quasarDPAってSPAが片手に降ってくるんでしょ」
「DP穴ネメシスの譜面は暗記すればできるって聞いた」
「quellって最強だというけど強さがよく分からない」
…DPに対してはこんな感じの印象を抱いている方が多いのではないでしょうか。あるいはボス曲については知名度も高いですが、それ以外のDPのみ☆12曲については意外と知られてないことも多いでしょう。
(例えばstarmineやgardenのDPAが☆12というのはご存知でしょうか?)
あるいは上記のような青天井のような難度の曲の存在から、DPに対して難しさや近付き難さを感じてる方も多いと思います。単純に鍵盤数もレーンの広さも倍ですしね。
・そういえばボス曲以外ってよく知らないや
という方には以下の動画がオススメ。上2つは譜面付き。
他にも良いDP曲紹介動画を教えていただければ追記します。
前作だとrainbow guiter weeps DPAが、今作だとFeel The Beet DPLや怪盗いいんちょDPAが個人的には非常に楽しいですね。
高難度に限らずともDPならではの譜面はたくさんあるのでぜひDPやってみましょう。TaQ曲と戦えるようになると脳汁ものですよ。
・やってみましょうと言われても、でも難しいんでしょ?
僕の答えとしては「SPと同じくらいには難しい」です。
天井はSP以上に果てしなく高いですが、少なくとも十段や皆伝まではSPと同じくらいの労力だと思います。個人差は大いにあるでしょうし異論は受け付けます。
また、難しさに関してもSPと方向性が違うので必ずしもDPの方が難しいとは限りません。特に連皿はDPの方が簡単です。
(僕の場合、灼熱以外のMass曲はDPしかクリアしてません。連皿苦手をこじらせてるのとSPをあまりプレイしてないというのが大きいですが)
認識や運指をイチから鍛え直さないといけないという点はありますが、逆にプレイすればするほど上手くなる感覚が味わえます。更には☆11くらいの混フレができるようになると本当にDPらしい楽しさが感じられます。
新しい音ゲーをプレイする感覚でぜひやってみましょう!ひとつの筐体でふたつのゲームができる!DPができるとすごいおトク!
・イチから鍛え直しって、SPに追いつくのに実際どのくらい掛かるの?
僕の体験談ですが、SP十段の僕がLincle稼働終了1週間前にDPを始めて、
- Lincle終了時(12年9月下旬):三段(10~20クレ)
- Tricoro稼働3ヶ月(13年1月):七段(累計100クレくらい)
- 13年6月上旬:八段(300クレくらい)
(この頃に専コン2台目を揃えてCS環境を整備。更にSP皆伝取得)
- 13年6月下旬:九段
- 13年7月上旬:十段
(当時の曲目はBLACK→satellite→雪妖精。累計クレはCS含め約800クレ相当?)
…というペースでした。ポップンの方に戻っていた時期もありますが、それも加味すると半年くらい頑張れば十段は取れた計算ですね。
現在の十段はEXUSIAとレゾンがいるため十段初取得時より厳しくなっているので実際にはもう少し掛かる可能性があります。十段取った時に☆12に緑が数曲点くかどうかでしたし…
十段取得後はTricoroの間はしばらくDPを離れて、その後SPADA稼働から本格的に復帰。SPADA稼働終了直前には12.3の緑が1/3くらい、CSEMP皆伝取得。クレ数はSPADAのみで約600クレ、CS含めるとその倍でしょうか。
結論として、十段まで約1000クレ、皆伝まで約2000クレという計算です。SPでも十段~皆伝間は1000クレで到達できるかどうかだと思うので、これが僕が「DPはSPと同等程度には難しい」と言った根拠です。
(僕はSPはほぼBMS専だったので皆伝までの正確なクレ数は分からないですが…)
・まとめ
DPやりましょう。是非やりましょう。
一緒にDPならではの混フレに快感を覚えたり、無理皿に轢き殺されたり、カイザーDPHにブチ切れたりしましょう。
DPはSPとは別ゲーではありますし実力の互換も利かない面が多いですが、新しい音ゲーを始めると思えばとても新鮮な感覚が得られます。
天井は高いですが皆伝取得までのハードルはSPとそこまで大きく違わないと思っています。是非!皆さん!DPをやりましょう!
え?始めるのが怖い?バッカお前…
・ところで
Q. 何でそんなに必死にDP布教してるの?
A. レベルの近いDPガチ勢少ないんですよ。十段~皆伝下位の方よろしければ是非1097-9170をライバル登録よろしくお願いします(土下座)