部屋の隅っこで書く技術ブログ

Web系企業勤務のエンジニアリングマネージャのブログです。技術ブログと称しつつ技術にまつわる個人的な話題が多めです。

【JavaScript】Vue.jsとES6の習作としてポーカー作った

f:id:expajp:20190613231800p:plain

Vue.jsとES6(ES2015)を勉強するための習作として、ポーカーを作ってみました。上の画像がそのままスクリーンショットです。

expajp.github.io

で、GitHubリポジトリがこちらですね。

github.com

2年ほど前にRubyRailsの勉強はじめてからほぼRubyしか書いてなかったのですが、その間にもJSの動向は気になっていました。

JSなんて添え物だったのに何だかすごいことになってるなあ……と思いつつ、「RubyRails覚えるのにとにかく集中して市場価値を確立しないと死ぬ」という状況だったので見て見ぬふりをせざるを得ず。

昨年の秋頃にProject Euler100問解答したのをきっかけにそろそろ見ないふりもできなくなり、Vue.jsとES6に手をつけることにしたのでした。

どういう流れで勉強したか

公式のチュートリアルを一通りやる → Vue.js入門の輪読会に参加する → なにか作るかー、と思ってVue.jsでブラックジャックを作ってみた - Qiita の写経を始める → 写経が終わったのでブラックジャックを発展させる形でポーカーを作り始める

Vue.js入門はこちらですね。

それから、ブラックジャックを扱った記事がこちら。

qiita.com

勉強にかかった期間は、

なので、Vue.js始めてからここまで9ヶ月ほどです。

開発の流れ

GitHubの草に重ねて画像を作ってみました。

f:id:expajp:20190613231946p:plain

上記の画像にあるように、

  • 最初はブラックジャックの写経
  • 次にポーカーの実装
  • パッケージを何気なく上げたら突然動かなくなってやる気をなくす
    • 全てを諦めてvue createを再度実行
    • 今度はテストを足そうと思ってJestを導入しても、動かずまたやる気をなくす
  • やっとJestが動いたのでJS関数のテストを作成する
    • そうすると今度はコンポーネントテストが動かないので、さらにやる気をなくす
    • 全てを諦めてvue createを再度実行
  • コンポーネントテストが実装できたのでやっと公開する

という流れでした。半年間のうち2ヶ月ほどはやる気をなくしてる計算ですね

やる気をなくしていた箇所が露骨に砂漠化している……

Vue.jsについて

これがjQueryつらい問題に対する回答なのかー、と感心しました。

jQueryつらい問題の実体って、

  • DOMがコード内で書き換えられるので、書き足す時に「DOMの現在の状態」を脳内で起こさないといけない
  • テキストボックスとボタンなど、双方向にバインディングする際に両方にイベントリスナが必要な上、実装にズレがあると動かない
  • 個別のDOM操作を手続き型言語のように行うので、設計を反映したコードになりにくい

あたりだと思うんですが、それぞれ、

という回答を与えています。

他にも、

  • 少しずつ置き換えられるので手元で試すのが簡単で、jQueryの代替として使える
  • SFCCSSのスコープを絞れる

などなどメリットは山のようにあります。

デメリットはTypeScriptとの食い合わせが悪いくらいでしょうか?

つらいと感じたのは、VueというよりはJSに起因したものでした。

ES6(ES2015)について

Vueを触るに当たって、2014年以前のまま止まっていた脳みそを動かすため、以下の本でES6を勉強しました。

便利だなと思うこと

昔の悪魔的な言語仕様に比べれば、だいぶ書きやすくなりました。

省略記法

一行だけの関数にfunctionとかreturnとかいちいち書きたくないので、アロー関数とその省略記法を重宝しました。

アロー関数使えば、「thisが呼び出し元の関数」とかいう謎仕様も発動しなくて快適です。

クラス構文と継承

JavaScriptオブジェクト指向言語っぽく書きたい!」と考える人は昔から多くいて、

www.atmarkit.co.jp

こんな記事があって自分も少しだけES5をこの書き方で書いた記憶があります。

というわけで昔から不可能ではなかったんですが、やっぱりclassがサポートされたり、値が関数であるプロパティをメソッドのように書けるのは便利です。

それから、ES5で無理やり書くのと違って継承が段違いで直感的です。

import/export

JSでもモジュール分割ができるようになりました。

昔はJSをファイル分けして、HTMLからの読み込み順を整えることでファイル分割してましたね。

Webpackが必要なのは今でもブラウザの方はそうやって全部読み込んで順番に実行するからだと思うんですが、実装時には読み込み順を意識しなくても良くなりました。

これ、ものすごく便利というかやっと実装されたかという感想です。

世間一般の言語はわざわざモジュール側でexportなんて書かなくても外部モジュールを読み込めるので、まだまだ発展の余地はあると思いますけどね。

テストツールがある

厳密にはES6の機能ではないですが、これはモジュール分割ができるようになったからこそ。

テストのないコードはすべてレガシーコードなのに、今までJSではまともにテストが書けませんでした。

これで、JSで開発するだけで負債が生まれまくるなんてことは避けられますね。

ところで、今回テストツールにはJestを使ったんですが、この記事が神でした

qiita.com

便利じゃないなと思うこと

importするときにいちいち関数名を指定させられる

例えばこれです。

import getScore from './getScore.js'

getScore.js で指定した名前で読み込ませてほしい……

ディレクトリごとimportするのが面倒

役を定義したクラスをすべてimportしている箇所があるんですが、こんなことになってます。

import { FourCard, None, RoyalStraightFlash, StraightFlash, TwoPair, Flash, FullHouse, OnePair, Straight, ThreeCard } from '../yaku'

で、src/yaku/index.js はこんな感じ。

export * from "./FourCard.js"
export * from "./None.js"
export * from "./RoyalStraightFlash.js"
export * from "./StraightFlash.js"
export * from "./TwoPair.js"
export * from "./Flash.js"
export * from "./FullHouse.js"
export * from "./OnePair.js"
export * from "./Straight.js"
export * from "./ThreeCard.js"

うーん、もうちょっとなんとかならないですかね。。。

index.jsにあたるコードは自動生成するとか……

パッケージの依存関係が簡単に壊れる

ほんっっっっっっとこれなんとかしてくれませんか……

計2ヶ月やる気をなくしていた原因はこれなんです、もうちょっとなんとかしてほしい……

ただ、vue-cliは優秀で、動かなくなった場合はボイラープレートから作り直して自分で書いたコードだけコピーするという手段が使えます。

gitリポジトリに一貫性を持たせるためにいろいろやらないといけないので、最終手段ですけど。

まだ良くわからないところ

非同期処理周り。Promiseって何?

ポーカーについて

仕様のこだわりポイント

細かいルールまで網羅されるように作りました。参考にしたのはこのページ。

www.nintendo.co.jp

ここのルールを参考に、ブタどうし以外では引き分けが生まれないように作りました。

ツーペアどうしになった場合、

同じ役同士では高いほうのペアを比較して、順位の高いほうが勝ち。 それも同じなら低いほうのペアを比較して、順位の高いほうが勝ち。 またそれも同じなら、高いほうのペアで♠を持っている人が勝ちとなります。

なんて処理がありますが、これもちゃんと実装されています。

ていうか、任天堂がこんなページ作ってるんですね。そういえばこの会社、今でもトランプ作ってるんだった。

技術的なこだわりポイント

これは勝敗判定のロジックです。

手札の情報は、例えば{ number: 13, suit: 'spade' }(スペードの13)のようなJSオブジェクトの配列になっているんですが、これに対して

  • 手札をラップして勝敗判定に必要な情報を返すHandクラス
  • ランクと同じ役どうしのときの比較基準を返すYakuクラス群
  • HandからYakuを生成するJudgingObjectFactory
  • Yakuどうしを比較するGame#judgeVictoryOrDefeat

と、丁寧に責任を分割して作っています。

ひとつ惜しむらくはGame#judgeVictoryOrDefeatの戻り値がYou Winなどの文字列であることで、勝敗オブジェクトを定義してそいつに喋らせればよかったかなと思っています。

まあ作りはじめてもう半年も経ってるし、直さずに公開することにしちゃいましたが。

全体的な感想

  • VueはjQueryつらい問題への素晴らしい回答
  • ES6もぐっと書きやすくなって好感触
  • なのに、パッケージの依存関係が壊れやすすぎるせいでたまに思い出したように触るのがつらすぎ、上2つが台無し

というところでした。

最後の性質が「専門家以外も使う」というJSの性質と極めて相性が良くないんですよね。

サーバサイドに軸足を置きつつ、つまみ食いのように触ることも許してほしいなあ。

でも、すぐ動くことやオブジェクト指向的な設計を書けるようになったことから開発自体は楽しいので、これからも追いかけていきたいと思っています。

ではでは。