【ニンテンドースイッチ】独断で決めた3本の名作、2本の駄作
どうも、のらぬこです。
発売後ずっと品薄状態だったニンテンドースイッチですが、ここ最近ようやく品薄状態から脱却してきたようで、量販店やネット通販サイト等でも適正価格で見かけることも増えてきました。
転売屋にマージン払うのが嫌で購入をためらっていた方も、ネット通販や家電量販店に足を運んでみると意外とすんなり購入できるかもしれません。
僕も去年の11月頃に定価で購入し、いくつかのゲームで遊んできました。そのなかには、超名作!と感じたものもあれば、流行ってるみたいだけど正直全然面白くなかったゲームもありました。
今回は、完全な僕の個人的主観で、ニンテンドースイッチのゲームで、買ってよかったゲーム、個人的には微妙だったゲームをそれぞれ紹介していきたいと思います。
買ってよかったゲーム編
ゼルダの伝説 ブレスオブワイルド
プレイ時間:230時間以上
ゼルダの伝説 ブレス オブ ザ ワイルド 1st トレーラー
ニンテンドースイッチが買えたらまず最初に買おうって決めていたゲームです。
3D系のアクションゲームにはほとんど手を出したことはなく、そもそもアクション系のゲームは苦手です。ですが、ネットの評判が非常に良かったことと、他に欲しいゲームがフルプライスのゲームでは特になかったので、とりあえずこれ買っとくか的な感じで購入しました。
ちなみに僕、任天堂が開発した3Dゲームというと、3頭身ぐらいの赤い帽子に青いズボンのおっさんが、英語で奇声を上げながら敵を踏みつぶしてる感じのゲームしか知りませんでした。 なので、これも大体そんな感じなんだろうなーと思ってました、ゲーム起動するまでは。
だから、ゲームを立ち上げて、短いオープニングデモを見て、主人公(リンク)が眠っていた場所から、外に出たときはとても衝撃を受けました。
そこには、洋ゲーっぽいリアルさこそないですが、どこまでも広がる美しい世界が広がっていました。
さらに、グラフィックは綺麗だけどそれ以外が・・・的なゲームは過去いくつも見てきましたが、このゲームは違いました。
グラフィックも、音楽も、ゲーム性も、どこをとっても最高でした。
自由に移動できるオープンワールド
歩く、走る、しゃがんでこっそり後ろから近づく、そして、泳いだり、壁をよじ登ったり、さらに、シナリオを進めればパラセール(パラシュートみたいなもの)での滑空や、野生の馬を捕まえて乗る、等の手段で、広大なフィールドを自由に移動できます。
スタミナの概念があるので、延々と泳ぎ続けたり、高い崖をひたすら上り続けるといったことはできませんが、繋がっているように見えるけど、実は見えない壁が・・・的な場所はありません。段差はよじ登ればいいし、川で隔てられていたら泳げばいい。
地形も様々で、火山近くのとても暑い土地、雪山の山頂付近のとても寒い土地、森や砂漠、平原等、それぞれに違った特色、違った敵が出てくるため、目的を忘れて世界をひたすら探検しているだけでもとても楽しいです。
単純化されているけど種類豊富なアクション
敵への攻撃手段も様々です。
たとえば、剣、弓(矢)で攻撃できるのはもちろん、盾で攻撃を弾き返したり、爆弾でダメージを与えたり、物を落としてダメージを与える等、色々な事ができます。
また、剣も弓矢も盾も、一度に何種類も持つことができて、簡単に切り替えることができるようになっています。
切り替え操作もさほど難しくありません。所定のボタンを押して装備パレットを出した後に、左右ボタンで使う装備を選択するだけです。
装備切り替えメニューを出している間は時間が止まってくれるので、落ち着いて操作することができ、慣れてくればとても快適です。
ジャンル的にはアクションゲームということで、シビアな操作が要求される場面もあります。ですが、メインシナリオクリアまでなら、アクションゲームが苦手な方でも、強い武器をどうにかして拾うとか、カバンいっぱいに回復料理を詰め込めこんでおけば真のエンディングまではしっかりと堪能できるようなバランスになっています。
ちなみに僕も、ラスボスは、ハートをほぼMAXまで強化して体力全快アイテムも5個くらい使って倒しました。
ただ、メインコンテンツはいいのですが、エキスパンションパックで追加される拡張コンテンツエリアはちょっと事情が違います。拡張コンテンツで追加されるエリアには、強い武器や回復アイテムなどの一切を持ち込むことができず、かつ、アクションが苦手な人向けの救済が存在しない(せめて休憩部屋でのセーブができれば・・・)ため、アクション苦手な方はクリアがとてもとても大変かもしれません。 エキスパンションパックは僕も購入したのですが、剣の試練(中位以降)がいまだクリアできず、未攻略のままとなってしまっております。
さて、話をもどしますが、バトル以外ではゲーム性とは関係のない無駄なアクション要素は極力省かれていたのも好印象でした。
例えば、川や湖で泳いでいる魚は捕まえて料理に使うことができるのですが、釣りという要素はありません。
じゃあどうするかというと、泳いで魚を追いかけて素手で捕まえるか、近くで爆弾を爆発させて、気絶して浮かんできたところをやっぱり素手で掴み取る、です。
僕は、釣り糸を垂らして十数秒待たされた後、魚が掛かったタイミングでボタンを押して(そのあとさらに釣り上げるためのアクションをこなして)魚を釣り上げる、というのをひたすら繰り返すアレがとても面倒で嫌いなので、こういう形にしてくれたのは有難かったです。
シンプルだけど深いシナリオと豊富なサブイベント
ゲームの最終目的は、復活した「魔獣ガノン」を倒すこと、です。
そして、その背後には、単に自由に冒険できるオープンワールドの世界、という以上に、長い歴史と壮大なシナリオが存在します。
序盤、チュートリアル+ゲームに最低限必要な要素の解放も兼ねたミッションはありますが、そのミッションが終われば完全に自由に冒険できます。 それも、完全にプレーヤーに丸投げではなく、一応、序盤に登場するおじいさんが、この後~~のほうに行けば、的なことを教えてくれるので、その通りにしてみると、なんとなく次に何をやってみるといいのかが少しづつ見えてくるようになっています。
世界中にいくつも建っている塔を目指したり、後述しますが世界中にいくつもある試練の祠と呼ばれるダンジョンを探したりしつつ少しづつ行動範囲を広げていけば、昔何が起こったのか、今何が起こっているのか、なんで自分はあそこで目覚めたのか、などが少しづつ分かるようになっています。本当に見事な演出です。
ガノン討伐を目指す、以外にも目標となることはたくさん用意されています。
例えば、ハート(HPの最大値)を増やしたり、がんばりゲージ(スタミナの最大値)を増やすには、攻略の証というものが必要になります。これは、世界中に100以上もある試練の祠(ギミック解除などの謎解きや、ガーディアンと呼ばれる中ボス的なモンスターを倒す等、様々な仕掛けが施された小さなダンジョンみたいなもの)を攻略することで手に入れることができるようになっています。
祠の近くに近づくと、センサーが教えてくれるのですが、マップに最初から表示されているわけではないので、探す楽しみ、クリアする楽しみの両方を満喫できます。
ほかにも、たくさんのサブクエストにチャレンジしたり、もてる装備アイテムの数を増やすための某アイテムを集めてみたり、出会ったモンスターや生き物を写真に撮ってコレクションしたり、目標として設定されたことはまだまだたくさんあります。
ちなみに、ひたすら同じことを何度もやってポイントをためると的な、いわゆる苦行クエみたいなものはありません(攻略必須ではありませんが、○○をいくつ集めて持ってきてほしいみたいなクエストはいくつかあります)。
本当に長いこと楽しめるゲームで、ニンテンドースイッチは持ってるけどゼルダは持ってない、という方も、これからニンテンドースイッチを買おうと思ってるけど、ゲームは何買おうか迷ってる方にもぜひともおすすめしたいと思います。
- 出版社/メーカー: 任天堂
- 発売日: 2017/03/03
- メディア: Video Game
- この商品を含むブログ (36件) を見る
ゼルダの伝説 ブレス オブ ザ ワイルド|オンラインコード版 - Switch
- 出版社/メーカー: 任天堂
- 発売日: 2017/03/02
- メディア: Software Download
- この商品を含むブログ (5件) を見る
【Switch用追加コンテンツ】 ゼルダの伝説 ブレス オブ ザ ワイルド エキスパンション・パス|オンラインコード版
- 出版社/メーカー: 任天堂
- 発売日: 2017/03/01
- メディア: Software Download
- この商品を含むブログ (8件) を見る
ヒューマンリソースマシーン(ダウンロード専用ソフト)
プレイ時間15時間以上
このゲーム、タイトルだけ見ると、特に黒い会社系社会人エンジニアな方にはギギギって来るものがあるかもしれません。 内容は、簡易アセンブラ系プログラミングパズルゲームです。 何を言っているかよくわからないと思いますが、もう少しわかりやすく書くと、PUSH、POP、MOV、JNE、JBE、JMPなどの命令を使い、与えられたプログラムのお題を解いていくゲームです。 やっぱり分からないという方のためにスクリーンショットも貼っておきます。
このスクショをみて、ああなるほどね、と思ったソフトウェアエンジニア気質な方でしたら楽しめるかと思います。
逆に、これを見て、?マークが頭に3つくらい浮かんだだけの方には正直あまり向かないかもしれません。
特に、エンジニアの方で、自分であれこれ考えてアルゴリズムを書くのが好きな人には非常に面白いと思います。 ただ、ググって出てきたコードをコピペ改変してものを作っていくタイプのエンジニアさんでも楽しめるかはわかりませんが(嘲笑)。
ちなみにお題の内容は、INPUTにわたってくる数字列を指定された条件で加工、フィルタして、OUTPUTに放り込むような感じです。
序盤は簡単ですが、終盤は(命令セットが貧弱なせいもあり)意外と骨があります。
そして、たとえゲームでも、自分が書いたプログラムが意図したとおりに動いてくれたらやっぱりうれしいです。
なので、一度始めるとなかなかやめられないし、一度クリアしたステージも、もうちょいステップ数(配置する命令の数)を減らせないかとかあれこれ考えてしまいます。
なお、このゲームダウンロード専用ゲームとなっておりまして、パッケージ版は存在しません。もし、興味持たれた方は、ニンテンドースイッチ内のストアからダウンロード版を購入してください。
マリオラビッツキングダムバトル
プレイ時間60時間以上
マリオ(とその仲間たち)、ラビッツ(ユービーアイソフトのキャラクターらしい、よく知らないけど)がを操作してステージをクリアしていくタクティクスSLGです。
ステージごとに、マリオ、ピーチなどの最大8人から3人を選んで出撃させます。
ユニットにはレベルの概念はないため、出撃させないと経験値がもらえずレベルアップできない、そしてますます出番がなくなるという残念なことにはなりません。
HPはワールドをクリアするごとに固定で増加していきます(後述のスキルポイントでも若干増やすことは可能です)。 また、攻撃力=武器の攻撃力は強い武器を入手することで強化していきます。こちらは、ステージクリアで自動的に入手する武器と、ミニゲーム的な要素で開放される武器の2種類があります。 どちらも、攻撃力は同じ(武器の見た目と追加効果が違うだけです)なので、コンプリートとかこだわらないのであればミニゲームスルーでも大丈夫と思います。
マップのギミック的要素や、特殊攻撃の数、敵キャラ、ボスキャラの数も、多すぎず、少なすぎず、単純すぎず、複雑すぎず、よいバランスだと思います。
また、マリオはジャンプで敵を踏んづけてダメージを与えられる、ルイージは移動力が大きいけどHPが少ない、ピーチは範囲回復ができるけど攻撃の手数が少ない、など、各キャラクター、とても分かりやすい個性も持っています。
難易度は比較的高めです。本編ステージは、パーフェクト(誰も死なずに指定ターン以内でクリア)を目指すとそれなりに難しいステージもありますが、とりあえずクリアするだけならそこまで難しくはありません(それでも、とりあえず出撃して、近くの敵から順番に撃破みたいな通り一遍の戦略では攻略は難しいと思います)。
半面、シナリオ攻略には必須ではない「チャレンジステージ」はかなり歯ごたえのあるステージも混ざっていて、難易度の高いステージを戦略を考えながらじっくり攻略するのが好きな方も楽しめると思います。
ステージごとに、相性のいいキャラクター、相性の悪いキャラクターがあるので、このステージ難しいなと思ったら、出撃キャラを変えてみると意外とすんなりクリアできたりします。
ステージ数もシナリオ、チャレンジ合わせて100くらいあるのでかなり長いこと楽しめると思います。
僕も、60時間ほど遊びましたが、未クリアのステージが10ほど残ってる感じで、もうしばらく遊べそうです。
- 出版社/メーカー: 任天堂
- 発売日: 2018/01/18
- メディア: Video Game
- この商品を含むブログ (2件) を見る
- 出版社/メーカー: 任天堂
- 発売日: 2018/01/17
- メディア: Software Download
- この商品を含むブログを見る
マリオ+ラビッツ キングダムバトル アドベンチャーパック|オンラインコード版
- 出版社/メーカー: 任天堂
- 発売日: 2018/01/17
- メディア: Software Download
- この商品を含むブログを見る
微妙だったゲーム
スーパーマリオオデッセイ
プレイ時間 10時間以上
そこそこの広さで細部までしっかりと作られた箱庭的3Dフィールドを、あちこち駆け回って進めていく3Dアクション系のマリオです。
スーパーマリオ3Dワールド(WiiU)はかなり楽しめたのですが、こちらは全然でした。
フィールドをとりあえず進んでいき、ギミックっぽい場所に出くわしたら近くの敵に帽子を当てる。 敵の姿になったらその敵の特殊能力を使ってギミックを通過する。
の繰り返しです。
敵キャラクターに帽子をあてると対象キャラに変身してその敵キャラの能力が使えるようになる、というのも今作のウリの一つらしいですが、自由に変身して、というわけではなく、各ステージ、ここではこのキャラに変身してギミックを通過してください、と言わんばかりに、いかにもな場所で、新しい敵がウロウロしていて、その能力を使ってギミックを通過して進んでいく感じです。
正直、あまり面白みがありませんでした。
また、各ワールド、寄り道をせずにメインルートのみを辿ってクリアすると、パワームーンの数が足りず先に進めなくなります。
先に進むには、少し頑張って寄り道をして、目立たない場所、わかりづらい場所に隠されたパワームーンを探さないといけません。
基本、とりあえずエンディングまで進めて、追加要素や探索は気が向いたらちょこちょこやるようなスタイルなので、正直とても面倒くさかったです(Wii Uのマリオも、ボスステージに進むには要所に隠してあるジェムを一定数集めないとダメとかいう要素が随所に埋め込まれていて、正直かなりウザかった)
また、コインを集めると、着せ替え衣装が買えたりするのですが、おっさんのコスプレとか全然興味ないので、そこもモチベーションが上がりませんでした(まあ、マリオだし、ほかにやりようがないというのもわかるんですが)。
グラフィックは綺麗だし、せめてエンディングまでは見ようと思って、各種お助け機能、お助けキャラ等を利用して、エンディングまで残り3ワールドというあたりまではプレイしたのですが、結局そこでやめてしまいました。
- 出版社/メーカー: 任天堂
- 発売日: 2017/10/27
- メディア: Video Game
- この商品を含むブログ (17件) を見る
- 出版社/メーカー: 任天堂
- 発売日: 2017/10/26
- メディア: Software Download
- この商品を含むブログ (4件) を見る
ゼノブレイド2
プレイ時間 10時間以上
ゼノブレイド2 Direct 2017.11.7 プレゼンテーション映像
ゼノブレイド(無印)が面白かったので、結構期待はしていたのですが、割と序盤で投げました。
ブログ記事やショッピングサイトなどでいろいろなレビューを見ることができますが、僕は中途半端なリアルと演出がダメでした。
ホムラ(PVで出てくる赤い髪の女の子)と合流して次の街にたどり着くくらいまでは楽しかったです。
でも、その街で、すごく萎える展開が待っておりました。
そこに到着後、とらわれた仲間を救出するために某施設に乗り込むシーンがあるのですが、施設内(室内)でも、時間は普通に経過し、朝になれば「おはようございます」、夜になれば「暗くなってきましたね」的なことを言ってくる仲間キャラ。待てコラ、屋内をずっと走り続けてたのにそのセリフはないだろう、と思いつつも,なるべく細かいことは気にしないことにしてプレイ続行。
しかし・・・
このゲーム、過去に行ったことのあるランドマーク(チェックポイント的なアレ)に、自由にワープできるシステムがあるのですが、仲間を救出し、あとは脱出するだけ、という状況だったので、施設の外にワープしてみたら普通にできました。でも、それでは脱出したことにはならないようで、イベントが進みません。
自分で歩き回って施設内の脱出ルートを探し、ギミックを解除して、製作者が意図した所定の出口に向かわないと話が進まないようです。
この中途半端な作りに嫌気がさして、モチベーションがなくなりました。
せめて、ドラクエでありがちな、「しかし、不思議な力でかき消された」の一文でも出てくればまだよかったのですが・・・・
- 出版社/メーカー: 任天堂
- 発売日: 2017/12/01
- メディア: Video Game
- この商品を含むブログ (7件) を見る
- 出版社/メーカー: 任天堂
- 発売日: 2017/11/30
- メディア: Software Download
- この商品を含むブログを見る
最後に
微妙だったゲームに関しては、え?そこがいいんじゃないの?とか、そんなことで投げたの?とか、いやいや、もっとこういう良さがあって、とか色々と思われることがある方も大勢いらっしゃる思いますが(でなければ、あんなに売れないと思うし)、あくまでも、個人的な主観で書いていますと、一応申し添えておきます。
個人的には、ニンテンドースイッチ買ったら、とりあえずゼルダやって、遊びつくしてきたなーと思ったら、レビューや動画を見ながら、自分の好きなジャンルのゲームを選んでいけばいいんじゃないかと思っております。
Nintendo Switch 本体 (ニンテンドースイッチ) 【Joy-Con (L) ネオンブルー/ (R) ネオンレッド】
- 出版社/メーカー: 任天堂
- 発売日: 2017/03/03
- メディア: Video Game
- この商品を含むブログ (35件) を見る
半分以上がゼルダの紹介記事になってしまいましたが、最後までお読みいただいてありがとうございました。
この記事がどなたかのご参考になれば幸いです。
PHPでフレームワークを使わずURLのルーティングをいい感じにやる
どうものらぬこです。
PHPでWebアプリを書くなら、SlimとかCakePHP等のフレームワークを使うのがおそらく一般的なのかと思います。
ところが、既存の環境を間借りして、そこにアプリを置くような場合等、PHPのバージョンが古い等の問題により、なかなかそうもいかない場合もあります。
先日やったお仕事で、既存のシステムの一部リプレイスをしたかったのですが、PHPのバージョンが古すぎてフレームワークが導入できず、また、ヘッダ、フッタ、サイドバーなどはSmartyのtemplateで書かれているのですが、そいつらは流用したいということがありました。
そんなわけで、僕がとった方針は、ロジック部分はPHPべた書きでゴリゴリ書いて、テンプレートエンジンだけSmartyを使う形で開発しました。
さて、例として、以下のようなURLパターンに対して機能を実装していくとします。
/search /categories /catgegory/4 /prefecture/10/category/2 /city/2011/category/1 /railway/20/stations ....
これらのURLを適切に解釈し、それぞれの機能に対応した Controller を呼び出し、パラメータ値に対応したModelをロードしていい感じに加工した後、適切なViewTemplateを呼び出すような仕組みは、何らかのフレームワークを使えばたいてい備わっています。
しかし、べた書きで書くような場合には、これらを自前で実装する必要があります。
Webを漁ってみたのですが、正規表現使った力業や、'/' で explode した後でひたすら条件分岐で頑張るなど、再利用性もメンテナンス性もまるでなさそうな方法しか見つからなかったので、URLパターンをSlim frameworkの Router みたいな記法で書ける URLマッチングメソッドを自分で書いてみました。
<?php function url_matcher( $inputUrl, $matchUrl, &$resultParams) { if (substr($inputUrl, -1) === '/') { $inputUrl = substr($inputUrl, 0, -1); } if (substr($matchUrl, -1) === '/') { $matchUrl = substr($matchUrl, -1); } $resultParams = array(); $inputUrlParts = explode('/', $inputUrl); $matchUrlParts = explode('/', $matchUrl); if ($inputUrl === '' && $matchUrl === '') { return true; } if (strpos($inputUrl, '/') !== 0 || strpos($matchUrl, '/') !== 0) { return false; } if (count($inputUrlParts) !== count($matchUrlParts)) { return false; } for ($index = 1; $index < count($inputUrlParts); $index++) { $path = preg_replace( '/^\{([^}]+)\}$/', '\1', $matchUrlParts[$index], 1, $replacedCount); if ($replacedCount === 0) { if ($inputUrlParts[$index] === '' || $inputUrlParts[$index] !== $matchUrlParts[$index]) { // path変数の重複によりエラー return false; } } else if ($replacedCount === 1) { if (isset($pathParams[$index]) || $inputUrlParts[$index] === '') { return false; } else { $resultParams[$path] = $inputUrlParts[$index]; } } else { // ルールに一致しない return false; } } return true; }
使い方はこんな感じです。
<?php function routing($method, $inputUrl) { $pathParams = null; if ($method === 'GET') { if (url_matcher($inputUrl, '/search'), $pathParams) { // 処理 } else if (url_matcher($inputUrl, '/category/{categoryID}', $pathParams)) { $categoryId = $pathParams['categoryID']; // 処理 } else if (url_matcher($inputUrl, '/prefecture/{prefectureID}/category/{categoryID}', $pathParams) { $prefectureId = $pathParams['prefectureID']; $categoryId = $pathParams['categoryID']; // 処理 } else if { .... } } else if ($method === 'POST') { .... } else { // page not found処理 exit; } }
こちら、PHP5.2、PHP7.1で動作確認済です。
適用する環境がせめてPHP5.3?5.4?以上であれば、url_matcher に function オブジェクトを渡すようにする等、もう少しやりようはあったのですが、このソースを動かす環境が PHP5.2とかいうまことに残念な環境であったため、こんな形になっております。
余談ですが、url_matcher で urlパターンにマッチした時の処理ですが、僕は以下のようなController もどきのクラスを作っています。
<?php abstract class Controller { protected $smarty = null; protected $mathod = null; protected $pathParams = null; protected $requestParams = null; public Controller($smarty, $method, $pathParams, $requestParams) { $this->smarty = $smarty; $this->method = $method; $this->pathParams = $pathParams; $this->requestParams = $requestParams; } abstract public function createModel(); abstract public function getTemplateFileName(); } class MyController extends Controller { public function createModel() { .... $this->smarty->assign(...); $this->smarty->assign(...); } public function getTemplateFileName() { return $smarty->getTemplateDirectory().'/hogehoge.tpl'; } }
まず、一致したURLルール毎に、Controllerの適切なサブクラスを作成し、以下のようなコードを書けば、一応MVCっぽい感じに実装できると思います。
<?php $controller->createModel(); $smarty->display($controller->getTemplateFileName());
パラメータのバリデーションチェック用のメソッドを用意したり、controller内の共通処理をserviceクラスを作ってそっちに移譲するなど、もう少しいろいろ頑張れば、ソースの見通しも良くなると思います。
ということで今回は、PHPで開発しているけど様々な事情でフレームワークが使えない方向け、簡易URLマッチング関数を実装してみたお話でした。
この記事が、どなたかのお役に立っていただければ幸いです。
使ってみた!Bluetoothでノイズキャンセリングな高性能ヘッドホン・イヤホン
どうも、のらぬこです。
以前、ニンテンドースイッチなどのbluetoothに対応していない機器を、Bluetooth接続対応のイヤホン等と、無線での接続を可能にする「Bluetoothオーディオトランスミッター」と呼ばれる製品の紹介記事を公開しました。
こちらの記事、大好評とはいかないまでも、比較的多くの方にお読みいただいたようで、僕もうれしい限りです。
さて、Bluetoothオーディオトランスミッターを使うには、当然ながらBluetooth対応のヘッドホン、イヤホン、スピーカーなどが必要になってきます。でも、前記事では、そちらについては全く触れていませんでした。
今回は、その辺の話を補ってみようという意味合いも込めて、僕が持っているBluetoothヘッドホン、イヤホンを紹介したいと思います。
イヤホン、ヘッドホンを使うシチュエーションは?
僕がヘッドホンを使うシチュエーション、利用シーンはだいたい下記のような感じです。家で使うことは滅多になく(夜遅くゲームするときに使うことが稀にあるくらい)、利用シーンは基本外出時です。
利用シーン
- 通勤中の電車内(割と轟音きつめな地下鉄区間も含む)
- ひとりでの外食中や休憩中。
- ファミレス、ファーストフード店などで、お昼ご飯や夜ご飯を食べてるときです
利用用途
- 音楽(ジャンルは、アニメ系、ゲームサントラ系などを中心に色々)鑑賞
- ゲーム機と接続して(3DS/PSVita/Nintendo Switch)
- 動画(主にアニメの録画番組)視聴
と、そこそこの騒音の中で様々な用途で使っている感じです。
今回紹介するヘッドホン、イヤホンは?
今回紹介するヘッドホン、イヤホンは、僕が持っている以下の5機種になります。
- MDR-ZX750BN
- MDR-ZX770BN
- MDR-EX31BN
- MDR-1000X
- h.ear in Wireless(MDR-EX750BT)
オーディオ機器メーカーとしてはソニーが特別好きというわけでもないのですが、気が付いたらソニー製品ばっかりになってしまいました(笑) 基本的に外出時(しかも、現在利用中の地下鉄、地下鉄の中でもたぶんかなり煩いです)の利用メインなので、1機種を除いてすべてノイズキャンセリング機能搭載となっています。
一応、ほかにもSHUREの「SE215 Special Edition」というイヤホンを持っていますが、Bluetoothの便利さに慣れてしまい、現在はお部屋の隅っこで眠っております。
一つずつ紹介
取り敢えず手持ちのイヤホン、ヘッドホンについて、良いところ、おすすめポイントなどを交えながら一つづつ紹介してみたいと思います。
MDR-ZX750BN
- 出版社/メーカー: ソニー SONY
- メディア: エレクトロニクス
- この商品を含むブログを見る
- 対応コーデック
- SBC/aptX
- 有線接続
- 可能
- NC性能
- ファミレス、ちょっとザワザワした喫茶店、地上を走る電車ならほぼ問題ないレベル、地下鉄はきつい
はじめて買ったBluetoothとノイズキャンセリング全部入りのヘッドホンです。比較的手の出しやすい価格で、Bluetooth+ノイズキャンセリングの両方がついたヘッドホンが欲しい!というお話でしたら、こちらのヘッドホンが一番のお薦めだと思います。
音質もまずまずで、低域から高域までちゃんと鳴らしてくれるし、こもった音でぼやーーっとした感じっという事もありません。
もちろん、同価格帯の有線ヘッドホンには流石に太刀打ちできませんが、機能を考えれば優秀なヘッドホンだと思います。
ただしこのヘッドホンの最大の問題は、すでに生産終了となっており、中古でしか出回っていないことです。中古であることがあまり気にならないのであれば、価格もそれほど高くないですし、今でも十分にお薦めできると思っています。
MDR-ZX770BN
ソニー SONY ワイヤレスノイズキャンセリングヘッドホン MDR-ZX770BN : Bluetooth対応 マイク付き ブラック MDR-ZX770BN B
- 出版社/メーカー: ソニー(SONY)
- 発売日: 2015/04/24
- メディア: Personal Computers
- この商品を含むブログ (1件) を見る
- 対応コーデック
- SBC/aptX
- 有線接続
- 可能(3.5インチミニジャックの接続口の部分が少しくぼんでおり、付属ケーブル以外では奥までしっかりと刺さらないかもしれません)
- NC性能
- ファミレス、ちょっとザワザワした喫茶店、地上を走る電車なら十分な性能、地下鉄はややきつい。「MDR-ZX750BN」よりも性能はよいと思います。
型番的にも価格的にも、最初に紹介した「MDR-ZX750BN」をちょっとグレードアップさせた感じの後継品。ただ、個人的な主観になりますが、音質の観点では1〜2段階グレードダウンした廉価版的な印象でした。
特に顕著なのが高域のかすれです。 シンバルなどの高域楽器はシャリシャリしたノイズがのっかっているような音になってしまっています。
また、「MDR-ZX750BN」と比べて音が籠もった感じになっています。
全体的な音のバランスはよいのですが、高域のかすれに関しては特に意識しなくても普通に気づくレベルです。
ただし、ノイズキャンセリングの性能は前機種からそこそこ向上しています。音質よりもノイズキャンセリングの方に重点を置いた機種なのかも知れません。
これらの2機種で検討するのであれば、中古全然ありですっていう方であれば「MDR-ZX750BN」をおすすめしたいです。
「MDR-ZX770BN」は、音質よりもノイズキャンセリング性能重視で、高級機種を買うほどの予算はなけど(それでも1万円くらいはかかってしまうのですが)性能のよいノイズキャンセリング+Bluetooth接続のヘッドホンがほしいっていう方には向いているかも知れません。
MDR-EX31BN
ソニー SONY ワイヤレスノイズキャンセリングイヤホン MDR-EX31BN : カナル型 Bluetooth対応 ブラック MDR-EX31BN B
- 出版社/メーカー: ソニー(SONY)
- 発売日: 2013/10/25
- メディア: エレクトロニクス
- この商品を含むブログ (9件) を見る
- 対応コーデック
- SBC/aptX
- 有線接続
- 不可能(Bluetooth接続専用になります。充電が切れた場合は音を聞くことができなくなります)
- NC性能
- あるのとないのでは多少は違う程度。そんなに煩くない場所では効果は感じられますが、電車内などそれなりにうるさい場所ではあまり役に立たない気がします。
こちらの商品のみ中古で購入しました。必要性は全く無かったのですが、値段が安かったので衝動買いしてしまった感じです。
付属しているイヤホンの音質は、新品価格で考えると割と微妙ですが、中古5000円未満というお値段ならまずまずと思います。
こちらのイヤホンは、Bluetooth受信部とイヤホンを、3.5インチミニジャックで接続して使う構造になっています。
したがって、標準で付いているイヤホン以外に、普通のイヤホンもつなぐことが出来るようになっています(もちろん、ノイズキャンセリングは使えなくなります)。
なので、好きなイヤホンを刺して Bluetoothオーディオトランスミッター的な使い方をすることも可能です。
MDR-1000X
ソニー SONY ワイヤレスノイズキャンセリングヘッドホン MDR-1000X : Bluetooth/ハイレゾ対応 マイク付き ブラック MDR-1000X B
- 出版社/メーカー: ソニー(SONY)
- メディア: エレクトロニクス
- この商品を含むブログを見る
- 対応コーデック
- SBC/aptX/LDAC
- 有線接続
- 可能(有線接続時にもノイズキャンセリング機能使用可)
- NC性能
- ファミレス、ちょっとザワザワした喫茶店、地上を走る電車では非常に快適です。さらに地下鉄等騒音がちょっと強めの環境でも申し分ない性能を発揮してくれます。ただ、地下鉄の中でもうるさい(と思う)京王線では、流石にちょっとボリューム盛らないと、動画音声などは聞きづらいこともあります。
こちらが僕が現在メインで使用しているヘッドホンになります。 というか、充電し忘れて使えない時以外は、基本これしか使ってませんw
性能については、値段が高いだけあって、音質、ノイズキャンセリング性能共に、他の機種を圧巻しています。
まず音質についてですが、低域から高域までアレンジされた感じもなくバランスよく比較的クリアに鳴らしてくれます。さらにノイズキャンセリング性能も抜群で、通常利用で不満に感じることはほぼないと思います。
BluetoothコーデックとしてSBC、aptXに加えて、「LDAC」というソニー独自規格のBluetoothコーデックが搭載されています。Xperiaシリーズなどの対応機器と接続すれば、ハイレゾ相当の高音質なサウンド再生も可能になっています。
一つ難点を挙げるとすれば、耳をすっぽり覆う形のヘッドホンなので、夏は蒸れることとくらいです。
予算があれば是非おすすめしたいヘッドホンです。
なお、2017年10月に発売された後継モデル(WH-1000XM2)では、ノイズキャンセリングの機能、性能が更に良くなっているようです。また、対応コーデックに「aptX HD」が追加されています。価格は少し上がってしまいますが、これから購入される方は、こちらも候補に入れてよいかと思います。
- 出版社/メーカー: ソニー(SONY)
- 発売日: 2017/10/07
- メディア: エレクトロニクス
- この商品を含むブログ (3件) を見る
h.ear in Wireless(MDR-EX750BT)
- 出版社/メーカー: ソニー(SONY)
- 発売日: 2016/03/12
- メディア: エレクトロニクス
- この商品を含むブログを見る
- 対応コーデック
- SBC/aptX/LDAC
- 有線接続
- 可能(付属の専用ケーブル必須)
- NC性能
- NC非搭載
MDR 1000Xの充電を忘れてた時や、荷物が多くてヘッドホンは持ち歩きたくない時などに使う予備機という位置づけで、カバンには常に入っています。
上で紹介した機種と比べると、くっきりとした若干高域寄りの音作りがされています。もちろん安いヘッドホンにありがちな音ではなく、クリアで聞きやすい音質になっています。
さらに、とても軽量で、首に掛けたときに邪魔になることもありません。
ただし、ノイズキャンセリング機能は積んでおらず、遮音性も特にないため、周囲がそこそこうるさい環境でじっくり聴くようなシチュエーションには不向きかもしれません(普通のイヤホンと同じです)。
ちなみに、こちらもイヤホンもLDAC対応なので、MDR-1000Xと同様に、Xperia等の対応機器では、より高音質なサウンド再生も可能になっています。
ちなみに、2017年の10月に、ノイズキャンセリング搭載した後継的な位置づけのモデル「WI-1000X」も発売されました。ノイズキャンセリング機能付き、ハイレゾ対応ワイヤレスイヤホンという条件であれば、間違いなくおすすめ出来る機種だと思うのですが、価格が高いのが難点です。
- 出版社/メーカー: ソニー(SONY)
- 発売日: 2017/10/07
- メディア: エレクトロニクス
- この商品を含むブログを見る
今後、新しいのを買うとしたら?
ソニーばっかりで恐縮ですが、「WI-1000X」は結構惹かれております。コンパクトでかさばることもなく、カタログスペックを見る限りでは、ノイズキャンセリングも音質もかなり頑張っているように感じました。
もし、MDR-1000Xが壊れてしまったら、今のところは1番の購入候補になると思います。
ということで、今回は、僕が使ったことがあるワイヤレスイヤホン、ヘッドホンを幾つか紹介させていただきました。
この記事がどなたかのご参考になれば幸いです。
amazon echo plus / google home miniのレビュー記事を書きました。 割と辛口ですがご興味ある方いらっしゃいましたらこちらもどうぞってことで。 noranuk0.hatenablog.com
最後までお読みいただいてありがとうございました。
スマホ落下を未然に防ぐ。安くて丈夫、紐が切れないお薦めストラップ
どうものらぬこです。
最近は、携帯電話、スマートフォンにストラップをつけている方も、林檎端末勢力に押され*1、見かけることも減ってきた気がします。
ですが、ガラケー、アンドロイド端末使いの方に限れば、アクセサリーとして、手が滑って端末を落としそうになったときの保険として、ストラップをつけている方も結構いらっしゃるんではないかと思っております。
さて、僕もガラケー使ってた頃、多分15年とか20年前くらいからずっとストラップ使ってますが、これ、携帯に括り付ける紐の部分が極めて脆く、すぐ切れちゃうんですよね。。。
安いものでも500円くらいはしましたし、買って数週間で紐が切れて使えなくなってしまったりするととても残念な気持ちになってしまいました。
僕と同じように、紐が切れない、長持ちするストラップを探している方もいらっしゃるんじゃないかと思い、今回は、ストラップを「手が滑って端末を落としそうになったときの保険」として使っている方向けに、僕が10年くらい使い続けている、とても頑丈なストラップを紹介していきます。
それがこちらです。
- 出版社/メーカー: 任天堂
- 発売日: 2008/09/04
- メディア: Video Game
- 購入: 1人 クリック: 3回
- この商品を含むブログ (4件) を見る
- メディア: Video Game
- クリック: 1回
- この商品を含むブログ (2件) を見る
機種変のときや、流石に薄汚れてきたと感じてきた時に交換はしていますが、それでも3年位は余裕で持つと思います。
こちら、かつて任天堂から発売されていたゲーム機「Wii」のコントローラ用のストラップなのですが、この紐がとても頑丈にできているのです。一応、Wiiのアクセサリーということになってはいますが、もちろんスマホでも使えます。
価格も1本100円〜200円程度で売られています。
ちなみにこのストラップ、Wiiの発売と同時に販売開始されたものなのですが、実は最初から丈夫だったわけではありません。
Wiiの発売後間もなく、海外で、Wiiリモコン(コントローラ)を振るような操作で遊んでいたところ、手が滑ってWiiリモコンが手から離れたと同時にストラップ紐が切れ、Wiiリモコンがテレビに激突しテレビが破損した、という事故がありました。 それを受け、任天堂が「多少乱暴に扱った程度では紐が切れない改良版」を用意した、という経緯があります。
つまり、現在出回っているWiiストラップは、「ストラップを手にはめた状態では多少振り回した程度では壊れない」程度の強度を持っている、と思っています。
ちなみに、紐の部分はこんな感じです。かなり太いです。
xperia Z5にとりつけてみたところです。ストラップの色が割りと派手なので、スマホやケースの色によっては合わせづらい可能性があるのが難点といえば難点。
丈夫でコスパもとても良いのですが、3つほど注意点があります。
まず1つ目は、ストラップが丈夫だから多少乱暴に扱っても平気というわけでは勿論ないということです。例えば、ストラップを腕に巻いてスマホを振り回したりすれば危ないのは勿論ですが、ストラップ紐が丈夫なため、スマホのストラップホールが壊れてしまうかもしれません。
2つ目は、ストラップ紐が太いのでストラップホールに通すのに結構苦労します。スマホのストラップホールサイズにも夜と思いますが、途中までねじ込んだ後、爪楊枝などを引っ掛けて紐を引っ張り出す、等のテクが必要なるかもしれません。
そして3つ目は、Wiiは既に過去の製品ということです。 このストラップもいつ市場から消え去ってしまっても不思議ではありません。かなり前から量販店で見かけることもなくなってしまいました。
値段も高くはないですし、丈夫なストラップがほしいなー、と思っていた方、お試しでご購入されてみても良いかと思います。
- 出版社/メーカー: 任天堂
- 発売日: 2008/09/04
- メディア: Video Game
- 購入: 1人 クリック: 3回
- この商品を含むブログ (4件) を見る
というわけで、今回の記事は以上となります。
この記事が、どなたかのお役に立っていただければ幸いです。
この怨み、地獄へ流します・・・ ~ iOSアプリ審査提出前のバリデーションフェーズで起きた悲劇を語る
どうも、のらぬこです。
完成したiOSデバイス向けのアプリをAppStoreで配信するには、林檎神の理不尽な審査を通過しなければならない。
xcodeで成果物を提出するための操作を行うと、まずはプロジェクト関連ファイルのバリデーションが実行される。
この段階で、例えば「アイコンのサイズが規定のサイズでキチンと作られているか」とか「そもそもちゃんとビルド通るか」等が確認される。
今回は、このプロジェクトコード一式のバリデーションで発生したエラーではまった話をしようと思う。
ITMS-90056
This Bundle ****/TabPageViewController.framework is invalid Thr Info.plist file is missing the required key: CFBundleVersion
内部で利用している「TabPageViewController」というフレームワークのInfo.plistがおかしい?必須項目であるCFBundleVersionというキーが存在しないというエラーのようだ。
軽く調べてみたが結局原因は不明のまま。TabPageViewControllerの取り込み方法をcarthageからcocoaPodに変更することで回避できた。
ITMS-90328
Your package contains a file Main.storyboadc/TabPageView.nib with a name that contains invalid characters. Avoid using control characters in the file names.
なんとなく翻訳してみると、「ファイル名に使っちゃいけない文字を使っている」と書かれているような気がする。だが、対象のファイルは “TabPageView.nib” と、使っちゃいけない文字とか全くなさげ。
解決編
原因と修正方法を先に書いてしまう。
まず原因の方だが、このエラーは、ストーリーボードに配置されたViewContorollerのstoryboardIDに変な文字(改行とかタブとかファイル名としてあまりよろしくない文字)が紛れ込んでいた場合に表示される。
ちなみに、そのIDがプログラムから全く参照されていない場合、リリース用にcode validationを掛けるまで「警告」「エラー」等は何も表示されないし、シミュレータや実機などで開発版を動かす際も特に不具合は発生しない。
したがって、原因や修正方法に関する知見を持たないままプロジェクトが最終局面を迎えてしまうと、最後の最後になって初めてこのエラーを目にすることとなる*1。
さて、次は修正方法だが、まずはプロジェクトに登録された全てのstoryboardファイル内を「
もし、見つからなかった場合は、このブログ記事の内容を読んでも解決策は見つからないと思うので、早々に立ち去って他の記事を探すことをオススメする。
見つかった場合、見つかった箇所周辺のxmlタグを眺めつつ、対象のViewControllerなどを特定し、storyBoardIdなどに特殊文字が紛れ込んでいないかを確認してみようか。
ただしここで注意していただきたいのは、xcodeのプロパティービューを見ても特におかしなところは見当たらない(ように見える)かもしれないことだ。
だがしかし
storyboardId欄などにフォーカスし、ctrl+A → ctrl+Cなどで全選択コピーをして、そのまま他のエディターなどに貼り付けてみると、たしかに妙な文字(僕の場合は
最も、とりあえず場所が特定できれば後はどうということはない。問題箇所を適切に修正すれば、このエラーは消えるはず。
調査編
修正は一瞬だったが原因の特定にはそれなりに苦労したので、せっかくだから修正完了までの作業プロセスも書いておく。
まずは、nibファイルが何物なのかと思って調べてみた。検索結果を流し読みしただけなのだが、どうやら画面レイアウト系のファイルのようで、アーカイブ時にstoryboardから生成されるファイルらしい。
そういえばstoryboardファイルの中身ってxmlなので、とりあえずテキストとして開いて TabPageView で検索してみるが、対象の文字列は見つからず。
次に、エラーコードやエラーメッセージ等で検索してみるも、xcode再起動してもう一度試してみれば?的なアドバイスはどこかにあった。一応やってみたけど当然ダメ。
とりあえず、TabPageView.nibというファイルを探してみることにした。
といっても、xcodeがビルドする際に中間ファイル的なものをどこに作るのかわからなかったので、以下のコマンドで対象ファイルっぽいものを探してみる。
$ find / --name TabPageView.nib 2>/dev/null /private/var/folders/...../Base.lproj/Main.storyboardcTabPageView.nib
発見。
見つかったディレクトリに移動して lsしてみる。
$ ls -la total 432 -rw-r--r-- 1 * * 7 10 13:08 ?TabPageView.nib drwxr-xr-x 40 * * 7 10 13:08 . drwxr-xr-x 4 * * 7 10 13:08 .. ... ...
「何かおかしい」
確かに、ファイル名先頭に不穏な文字がくっついている。
$ cat <TAB> ^HTabPageView.nib
「H」を文字コードに直すと「0x08」。
「お前、タブ文字か・・・・」
そこで、ふと気づき、Main.storyboardを一旦カラにし、素のViewControllerを一つ配置した状態で再Validationをかけてみる
言うまでもなく、当然起動直後にクラッシュするとは思うが、少なくともValidationは通った。
storyboardをもとに戻し、配置されているViewControllerを1つずつ削除しながら、どのViewControllerを削除したときにValidationが通らなくなるかを確認しつつ、問題となっているViewControllerを特定する。
特定ができれば、あとは対象のViewControllerがxmlのどこに配置されているかを確認し、xmlの対象箇所を凝視して何かおかしそうな場所がないかを確認すればいい。
原因が特定できればあとは修正するだけだ。
上の「解決編」で書かれたことを実践し、問題を修正。その後、再度バリデーションをかければ、少なくとこのエラーは消えているはずだ。
最後に
エラーの原因解りづらいわ、そもそもxcodeがエラー箇所を正しく指摘してくれないわ、「ファイル名にコントロールコードが含まれてるからダメ」とかエラーコードまで定義されてる割にバッグ実行の為のビルドは成功するし、シミュレータ実機デバッグ共に問題なし何だが?
UXのなんたるかについて、Microsoft VisualStudio開発チームあたりから一世紀ほど学んでから出直してきてほしい。
取り敢えず彼らには、不幸の手紙と藁人形と五寸釘10セット程を是非とも寄贈して差し上げたいと思った次第。
- 出版社/メーカー: 快適生活百貨店
- メディア: Baby Product
- この商品を含むブログを見る
地獄少女閻魔あい ウィッグ 制服 スカート 数珠 藁人形 5点セット [並行輸入品]
- 出版社/メーカー: ノーブランド
- メディア:
- この商品を含むブログを見る
今回の記事は以上だ。
*1:僕のように
俺の右腕に眠りし黒竜よ!力を貸してくれっ! ドッカァー!コンポォォーーッズ!!
どうものらぬこです。
某社関係者のどなたかが、類似するエントリー名で記事書いてたら申し訳ないので一応検索してみたのですが、そういうのはなさそうなので、取り敢えずこのフレーズ頂いときます<(__)>*1
というわけで、今回は Docker の話をしようと思います。
dockerとは
今更な話だし、検索すれば答えもたくさん出てくるだろうけど、取り敢えず僕の理解では「軽量でそこそこセキュアで再利用可能なアプリケーションorデータコンテナ」という認識です。
コンテナは基本的にはLinuxOSベースの仮想環境です。マイクロソフト社に御布施をしてWindows Server 2016を導入すれば、Windowsベースの仮想環境を用意することも可能みたいです。 でもそんなお金ないし、僕は今のところその必要性も感じてないので、触ってみたことはありません。
なお、コンテナはあくまで仮想環境なので、実PCで直接動かすことはできません。Dockerというソフトウェアを使って、ホストOSの上に構築した仮想的なLinux環境として動かします。
僕がDockerを触ってみようと思った訳
さて、PHPを使われている方の間では常識なのかもしれませんが、このPHPという言語はなかなか曲者で、マイナーバージョンレベルの更新ですら(7.0->7.1等)、上位互換性(バージョンアップしても今まで動いてたコードはちゃんと動くように作ってるよ的な)が割りと確保されていないことも多いという、個人的には割りとFA?って感じの特徴があります。
ローカルで確認したいとき等、一々PHPのバージョン切り替えるのめんどいし、そういえばdockerとか使えばなんか色々はかどるんじゃないかなとなんとなく思ったのが、最近dockerの勉強を始めたきっかけです
dockerの全貌をなんとなく理解してみる
ある概念を新しく勉強するときは、自分の知っている類似の概念に置き換えてイメージしていくと理解がしやすいと考えています。
dokcerもそんな感じで覚えていきました。
docker hub
Docker Image
- UbuntuやcentOSなどのLiveCD(DVD)メディア的なもの。docker hubに公開されているものをそのまま使うこともできるし、自分でほぼ一から作ることもできる。また、docker hubで公開されているイメージをさらに自分でカスタマイズすることもできる。
- LiveCDと違うのは以下の2つ。
- LiveCDと違って、PCから直接起動することはできない。 * 代わりに、DockerEngineと呼ばれる、DockerImageを動かすための仮想環境を構築するソフトウェア(VMWareとかVirtualPCみたいなやつ)使って、起動中のOSの上に仮想的なLinux環境を新しく立ち上げる(この起動中の環境のことをコンテナっていう)。
- LiveCDは読み取り専用だけど(HDDとかUSBメモリーをマウントすればもちろんマウント先には書き込み可能)、DockerImageには書き込みもできる。
- /root だろうが /etc だろうがどこでも書き込み可能。
- 書き込まれた内容ははDockerImageの中に直接保存されるのではなく、「どのファイルをどういう風に書き換えた」という差分情報のみがDocker Imageとは別の場所に保存されるため、追加、削除、変更内容は元のイメージには影響しない。
- たとえ「rm -rf /」してしまい絶望に飲み込まれたとしても、元のイメージから新しいコンテナを起動すれば全ての変更は無かったことになっています。
Dockerfile
Docker Container
- 起動中のDockerImageのことをコンテナって呼びます。
- 1つのイメージから複数のコンテナを起動することができます。
- 1つのイメージから複数のコンテナを起動しても、それらはお互いに干渉しません。
- 例えば、コンテナAで /etc/apache2/httpd.conf を書き換えても、その変更は コンテナBには適用されません。
- 1つのイメージから複数のコンテナを起動しても、それらはお互いに干渉しません。
- 色々な種類のイメージを用意すれば、色々な種類のコンテナを同時に起動することも勿論できます
- コンテナのリソース(ファイルシステムだったりネットワークリソースだったり)は基本的に隔離されているので、共有はできない。
- ただし、起動時にパラメータで指定したり、Dockerfileに設定を記載しておくことで、ネットワークの特定のポートを使用して通信したり、ファイルシステムの特定のパスをホストOS(Docker Containerを動かしているOS)と共有することなどが可能。
docker-compose
- 本エントリーのタイトルにもなった、なんとなくかっこいいコマンド
- このフレーズは、前職の馬場さん(仮名)によって生み出されたもので、サービスをデプロイするには、このフレーズを馬場さん(仮名)にシャウトしていただかなければならないという暗黙のルールがありました。
- ただし、「俺の右腕に~」の部分は
本人が恥ずかしがって省略されていました
- ただし、「俺の右腕に~」の部分は
- このフレーズは、前職の馬場さん(仮名)によって生み出されたもので、サービスをデプロイするには、このフレーズを馬場さん(仮名)にシャウトしていただかなければならないという暗黙のルールがありました。
- 複数の Dockerコンテナが連携して動作するようなシステム(例えば、nginx+PHPが動いてるコンテナとPostgreSQLが動いているコンテナとRedisが動いているコンテナ、など)で、複数コンテナの連携(ネットワークの接続設定やファイルシステムの共有っぽい設定、各コンテナの起動順序など)をいい感じにいろいろやってくれる、確かにすごいコマンド。
- それぞれのコンテナをどういう風に連携させるのかは docker-compose.yml というファイルに書いておく。
- 現在勉強中。
- 本エントリーのタイトルにもなった、なんとなくかっこいいコマンド
dockerの使い方
動作環境やインストール方法、動作原理なんかは検索すれば腐るほど出てくるのでその辺は書きません。
ここでは、使い始めるとかならず使うコマンドを、僕がよく使うコマンドを中心に備忘録的にまとめておきます。
Docker hubからImage 取得
$ docker pull <リポジトリ名:タグ名> * alpine:latest -> 軽量コンテナ向け * busybox:latest -> データコンテナ向け
alpine linux + apache な Dockerfile
- alpine linux は、Docker Image(基本パック)のサイズ僅か6Mb程のとてもコンパクトなlinuxDistribution
- 起動後のシェルで
# apachectl start
で apacheが起動する# wget http://localhost:80/
で index.html が落ちてくれば成功
FROM alpine:3.6 RUN apk add --no-cache apache2 apache2-utils && \ mkdir /run/apache2 && \ chown apache:apache /run/apache2
Dockerfile -> image 作成
$ docker build [-t <イメージにつける名前] .
作成済Imageの一覧を出力
$ docker images
不要になったImage 削除
$ docker rmi <リポジトリ名:タグ名 or イメージID>
Imageをまとめて削除
$ docker images | awk '{print $3}' | xargs docker rmi * 一部を消したいときは間にgrepなどでフィルタ
作成済Imageからコンテナを作成&起動
オプションがいっぱいありますが、コンテナのTCPポートをホストOS(Dockerを起動しているOS)のTCPポートにマップしたり、ホストOSのファイルシステムパスをコンテナから見えるようにしたりといろいろな設定ができます
$ docker run [-d] [-it] [-p <ホストポート番号>:<コンテナポート番号>] [-v <ホストパス>:<コンテナパス>] [--rm] [--name <コンテナにつける名前>] <イメージ名:タグ名 or イメージID> <起動時に実行するコマンド>
コンテナ一覧
$ docker ps * 起動中コンテナ $ docker ps -a * 停止中コンテナ
コンテナの内部情報を表示
$ docker inspect <コンテナ名 or コンテナID>
コンテナ->イメージ作成
これは、動作中のコンテナのファイルシステムの状態をDocker Imageとして保存するコマンドです。
$ docker commit <コンテナ名 or コンテナID> <イメージ名>
Container 削除
$ docker rm <コンテナ名 or コンテナID>
Container まとめて削除
$ docker ps -a | awk '{print $1}' | xargs docker rm * 一部を消したいときは間にgrepなどでフィルタ
参照されていないデータボリュームを削除
$ docker volume ls $ docker volume prune
Dockerの使いどころ
Dockerの使いどころを僕なりに考えてみました。
開発環境として
例えば、Java,PHP,Ruby等の開発言語 + RDB + Redis + ElasticSearch等のシステムをローカル環境で構築するのはちょっと大変ですが、Dockerで nginxのコンテナ、Java(+ApplicationServer)のコンテナ、RDBのコンテナ…等を用意して、それらの関連を docker-compose.yml で管理してあげれば色々楽ができそうです。
チーム開発をしているような場合には、新しいメンバーが入ってきたときも、それぞれのツールの指定されたバージョンをダウンロードして手順書に従ってインストールなんて面倒なことを毎回やらなくても、Docker入れて、そこのdocker-compose.yml使えば環境できるという状態にすることもできるはずと思います。
例えば、PHPのバージョンアップテストをしたい等の目的で、一時的に複数バージョンのPHPを使いたいときなども、なんかうまくやってくれるはず!
開発周辺ツールのホスト環境として
jenkins とか redmine とか selenium + firefox driver の docker imageや docker-compose.yml などは検索すれば簡単に見つかります。
それぞれの環境のために、サーバ用意してOS入れてRubyだのJavaだの入れてRDB入れてREADME.md見ながらconfig設定して〜をやらなくても、簡単に環境を作ることができるはずです。
「コピペ万歳」です!
テストデータがたっぷり詰まったRDBの格納場所として
このエントリー内では特に説明しませんでしたが、Dokcerはアプリケーションコンテナとして使用する方法の他に、データコンテナとして使用することもできます。
マスターデータのみが入ったクリーンな環境や、リグレッションテスト向けに、毎回同じテストデータが入った環境を簡単に作ることができるようになります。
最後に
Dockerをうまく活用できれば確かに色々捗ることも増えそうです。
でも、夢は広がっていますが、この辺を正しく理解して活用出来るようになるには、もう少し勉強が必要のようです。
余談ですが、1冊くらい書籍も読んでおこうかと思って、先日オライリー本を買いました。
安定のオライリー品質で、内容もわかりやすいし翻訳もとても読みやすいです。
- 作者: Adrian Mouat,Sky株式会社玉川竜司
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/08/17
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
というわけで、今回の話は以上となります。
お読みいただいてありがとうございました。
俺のPHPがこんなに遅いわけがない 〜メソッドキャッシュのお話〜
どうものらぬこです。
最近仕事でPHPを使い始めました。
というわけで、今回はPHPの話でもしようかと思います。
さて、2年ほど前に在籍していた会社で開発していたシステムの話になるのですが、そのシステムが抱えるDBが、規模が巨大だったりだとか、それなりに複雑なクエリーをいくつも投げなきゃいけないとかありまして、パフォーマンスを出すのに割と苦労していたことがありました。
その時は、一緒に仕事をしていた「自称」天才の某中国人様に、『「クラス名+メソッド名+引数の値をつなげたもの」をキーとして、「戻り値の値」をメソッド呼び出しを丸ごとキャッシュとして保持してくれる仕組み』なるものを作ってもらいまして各種諸問題を解決していただいていたのは今では、今では良い思い出です。
ちなみに、当時はJAVAで開発していたのですが、今回、それと同じような仕組みをPHPで作ってみたいと思います。
今回作るもの
クラス内のインスタンスメソッドの呼び出しをフックして、「クラス名+メソッド名+引数の値をつなげたもの」をキーとして、「戻り値の値」をキャッシュする仕組みを作ります。
既存のシステムになるべく簡単に組み込めるものにします。
キャッシュする部分、キャッシュからデータを取得する部分の実装は適当です(Redisなどのミドルウェア使うなりPHPのプロセス内に Hashなどで保持しとくなりご自由にということで)。
お題として、DBに保存された何らかのマスターデータを問い合わせるというシーンを想定して、DBへの問い合わせ部分(IDを渡すとIDに対応したレコードを返してくれるメソッド)をキャッシュしてみます。
前提となる開発・実行環境の話
僕の環境は下記のような感じです。
- mac mini 2014
- PHP 7.1系(5.6以降なら多分動く)
- postgreSQL 9.6系(サンプルコード動かすのに使ってます)
それほど特殊なことをしているわけではないので、PHP5.6以降(多分もうちょっと古いバージョンでも大丈夫)な環境であれば動作すると思います。
また、組み込み先のプロジェクトは、キャッシュ化したいモジュールが class として定義されていることが前提です。
.phtml 等の htmlなんだかphpなんだか良くわからないコードや、関数という概念が存在しない残念なコード等には組み込むことができません。
早速作ってみる
取り敢えず、コード載せときます。説明とかは後回しで。
キャッシュの仕組みを実装しているコード
まずは、メソッドキャッシュの仕組みを実装しているコードを載せておきます。
コードの中身は後で説明するので、中身わかる方は眺めていただいてもいいですし、よくわからない方は読み飛ばしていただいて大丈夫です。
<?php class MethodCache { private $_instance; private static $_className; public function __construct($instance) { $this->_instance = $instance; $ref = new ReflectionClass($instance); self::$_className = $ref->getName(); } private static $cached = Array(); private function get_cache($key, &$value) { if (isset(self::$cached[$key])) { $value = unserialize(self::$cached[$key]); return true; } else { return false; } } private function put_cache($key, $value) { self::$cached[$key] = serialize($value); } public function __call($method, $arguments) { $calledMethod = self::$_className . '->' . $method . ':' . json_encode($arguments, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); $ret = null; if (!$this->get_cache($calledMethod, $ret)) { $ret = call_user_func_array(array($this->_instance, $method), $arguments); $this->put_cache($calledMethod, $ret); } return $ret; } public function __get($key) { return $this->_instance->$key; } public function __set($key, $value) { $this->_instance->$key = $value; } }
なお、get_cache() がキャッシュ済データを取得するメソッド, put_cache()がキャッシュに値を追加するメソッドです。
これらのメソッドの中身はサンプル用に適当に作っただけなので(一応、キャッシュするという機能は持っていますが)、Redisなどのミドルウェアを使うように適宜置き換えていただければと思います。 また、実運用ではキャッシュの破棄タイミングなども考慮する必要があるかと思います。
サンプルを作って動かしてみる
ということで、取り敢えずサンプル的なものを作って、実際に動かしてみたいと思います。
なお、phpの5.6以上と、遊び用途で使える適当なRDBが使えることが前提です。
僕の環境は、上の方でも一回書きましたが、php7.1、postgreSQL9.6です。
RDBの準備
まずは、RDBに「id」という名前のprimary key を持つテスト用のテーブルを適当に用意して、データを100件ほどインサートしておきます。 列名などはなんでも構いません。
作業環境を整える
RDBの準備ができたら、ソースの作成に入ります。
まずは適当な作業ディレクトリに移動して、以下のコマンドを打ち込んでください。
mkdir intercepter mkdir dao curl -sS https://getcomposer.org/installer | php
続いて、以下のファイルを順に作成、保存してください。
intercepter/MethodCache.php
まずは、前項で載せた、メソッドキャッシュの仕組みを実装しているコードを intercepter/MethodCache.php
という名前で保存してください。
composer.json
PHPな方にはおなじみのcomposer.json です。 メソッドキャッシュの仕組み自体には不要なのですが、サンプルとしてDBにつなぐために illuminate-database というモジュールを使用しています。
{ "autoload": { "psr-4": { "Dao\\" : "dao/", "" : "intercepter/" } }, "require": { "illuminate/database": "^5.4", "illuminate/events": "^5.4" } }
./dao/ExampleDao.php
illuminate-databaseのモジュールを利用して、DBから値を取ってくるクラス(いわゆるDao)クラスです。
<?php namespace Dao; use Illuminate\Database\Capsule\Manager as Capsule; class ExampleDao { private static $instance = null; private function __construct() { } public static function instance() { if (is_null(self::$instance)) { self::$instance = new \MethodCache(new ExampleDao()); } return self::$instance; } public function findBy($id) { return Capsule::table('test.my_data')->where('id', $id)->first(); } }
./test.php
最後のファイルは、サンプルの本体です。
<?php require_once __DIR__ . "/vendor/autoload.php"; use Illuminate\Database\Capsule\Manager as Capsule; use Illuminate\Events\Dispatcher; use Illuminate\Container\Container; $capsule = new Capsule; $capsule->addConnection([ 'driver' => 'pgsql', 'host' => 'localhost', 'database' => 'example', 'username' => 'noranuk0', 'password' => 'password', 'charset' => 'utf8', 'collation' => 'utf8_unicode_ci', 'prefix' => '', ]); $capsule->setEventDispatcher(new Dispatcher(new Container)); $capsule->setAsGlobal(); $capsule->bootEloquent(); $dao = Dao\ExampleDao::instance(); for ($times = 1; $times < 10; $times++) { $i = 0; $timeStart = microtime(true); for($i = 1; $i <= 100; $i++) { $dao->findBy($i); } $timePassed = microtime(true) - $timeStart; $timePassed *= 1000; print("{$times}回目:{$timePassed}ms\n"); }
なお、DB接続の部分のパラメータは環境に合わせて適切に設定してください。
composer の実行
実際にサンプルを動かす前に、composerを使いautoloadの設定と必要なモジュールのインストールを行います。
以下のコマンドをタイプしてください。
composer installer composer upate
動かしてみようか
ここまでの作業で、サンプルは完成(のはず)です。
早速動かしてみます。
環境により実行時間は異なってくると思いますが、キャッシュが効いている2回目以降は爆速みたいな結果が出てくると思います。
1回目:47.780990600586ms 2回目:0.20217895507812ms 3回目:0.1981258392334ms 4回目:0.22983551025391ms 5回目:0.22292137145996ms 6回目:0.24795532226562ms 7回目:0.1990795135498ms 8回目:0.20503997802734ms 9回目:0.20503997802734ms
既存コードへの取り込み方
高速化したいクラスのインスタンスを生成する際、そのクラスのインスタンスを直接生成するのではなく、new MethodCache(...)
で囲います。
self::$instance = new \MethodCache(new ExampleDao());
こんな感じです。
これで、class内に定義されたメソッドは全てキャッシュ対象となります。
クラスのインスタンスメソッドが呼び出されたときに、過去に同一の引数で呼び出されたことがあり(かつキャッシュが残っていれば)元のメソッドは呼び出さず、キャッシュされた値を返します。
原理
例えば、こんなコードが合ったとします。
$dao = new MethodCache(new ExampleDao());
$dao->findBy($id);
findBy()メソッドは ExampleDao に定義されたメソッドで、MethodCache class には該当メソッドがありません。
PHPで、存在しないメソッドが呼ばれると、 __call() というマジックメソッドが呼ばれます。
今回は、このメソッドの中で、キャッシュがあればそれを返し、なければ元のclassのメソッドを呼び出す、ということをやっております。
課題
class内のメソッドを何でもかんでもキャッシュしたら都合が悪い場合も勿論あると思います。
例えば、取得系のメソッドはキャッシュしたいけど、追加、更新系のメソッドはキャッシュしたくない、などです。
メソッド名で、キャッシュする、しないを判断する仕組みを間に挟んだり、メソッドアノテーション的なもの(PHPにあったっけ・・・?)でなんとかする等、方法はあると思います。
取り敢えず、そろそろ書くのも飽きてきたのと眠くなってきたので、この辺のことはまた今度気が向いたら考えることにします。
取り敢えず、今日の話は、PHPでもAOP的な仕組みを使って、メソッドキャッシュみたいなこともできるよっていう部分の紹介までということで。
最後に
今回の記事の参考にさせていただいた記事の紹介です。
こちらの記事でメソッドの実行時間を取得する目的で使われている仕組みを、メソッドキャッシュのために使ってみました。
大変参考になりました。どうもありがとうございましたm(__)m
ということで、今回のお話は以上となります。
この記事が、PHPな方々にとって何かの参考になれば幸いです。
- 作者: 大重美幸
- 出版社/メーカー: ソーテック社
- 発売日: 2016/07/01
- メディア: 単行本
- この商品を含むブログを見る