検索キーワード「���������������」に一致する投稿を日付順に表示しています。 関連性の高い順 すべての投稿を表示
検索キーワード「���������������」に一致する投稿を日付順に表示しています。 関連性の高い順 すべての投稿を表示

2021年12月1日水曜日

セキュリティを一切考慮しないMMORPGを開発するとどうなるか

どうもご無沙汰しております。本Blogが私の年1回の生存報告、兼、アドベントカレンダー用と相成って久しいですが、今年も一発恒例行事として筆を取らせていただきたいと思います。

今年、私が話題に取り上げますのは、とあるゲームです。Amazon Game Studiosという会社が開発・リリースしました、New WorldというMMORPGについてご紹介させていただきたいのです。ゲームの話題には一切興味がない読者諸君も、どうか少し我慢して、私に騙されたと思って最後まで話を聞いていただけませんでしょうか。そもそも、あのAmazonが開発したMMORPGというのですから、どれほどゲームに興味がなくても、技術に興味のある方でしたら、少しは興味深く感じられるのではないでしょうか?

けして後悔はさせませんよ。悪い方向にね。


さて、ゲームに何ら興味知識のない方にもわかるように少し解説を入れさせていただきますと、MMORPGというのは「数千人単位の人間がネットワーク上に構築された一つの世界を共有するRPG」です。要するにSAOです・・・いや、この説明だと最近の若いのには通じないですかね・・・まぁそういう感じのアレで、要するに滅茶苦茶多数の人間がサーバーに同時接続するゲームってことです。そして説明するまでもございませんが、Amazonという会社は世界で最も巨大なクラウドサービスの一つを展開している会社であります。我々技術畑の人間がシンプルに連想するのは、これほど相性の良い組み合わせはないに違いない、そうですね?

実際、発売前から私もそう思っていましたし、発売された後も、彼らはAmazonの名に相応しい仕事を見せつけてくれました。発売前から話題の合った本作はあれよあれよという間に最大同時接続90万人を記録するモンスターゲームに成り上がったのです。いいですか、90万人同時接続ですよ、90万人。90万DAUとか、90万PV/dayとか、90万Session/dayだとか、そういう雑魚みたいな指標ではありません、同時接続で90万です。貴方は90万の同時接続とリアルタイムレスポンスを保証できるシステムを構築できますか?言うまでも有りませんが私ならその場で全く不可能だと匙を投げますね。

さすがは開発元がAmazonの名を冠するゲーム会社だけあって、サーバーは相当な負荷に耐えきったと言えます。最大同時接続90万人をリリース直後から支えられるMMORPGというのはなかなか世に存在するものではありません。私も思わず「やっぱりAmazonはすごい」と驚嘆したものです。


ですが、我々は後から思い知ることになります。何故、彼らのサーバーが、同時接続90万という途方も無いアクセスに耐えることが出来たのか、その本当の理由を。

・・・サーバーが何もしていないからです。


dupe, exploit, cheatの軌跡 

先に説明したとおり、MMORPGというのはネットワーク上に構築された一つの世界を共有するゲームです。つまり、プレイヤーは全員常時サーバーにリアルタイムで接続された状態になっていますし、必然、全てのプレイヤーのデータはサーバ上で管理されています。

普通はね。

だって、各自のローカルサイドでプレイヤーのデータが管理されていたら、皆が好き勝手にローカルサイドでセーブデータなりメモリなりを書き換えたら、簡単にお金やアイテムが無限に増殖されてしまうでしょう?それでは皆のゲームが成り立ちませんから困りますね?そういう悪いことをゲームで行う・・・チートをする人間は、ここ数年右肩上がりに増えておりますから、ゲームを作る側も畢竟、高レベルのチート対策をゲームに組み入れるのが当然の事項となっているわけです。

そう、だから、普通は、どんなMMORPGを作るときもね、チート対策をするんですよ。

普通はね。


さて、あれはゲームがリリースされて30日もしたころでしょうか。

コミュニティの中で「アイテムが増殖できる」だとか「Goldが無限に増やせる」だとか、そういう噂が流れ始めました。

最初はただの噂だと思われていたのですが、1000万Goldを超える所持金や、ゲーム内で最も貴重なVoidmetalと呼ばれる金属を数千個単位で所持するスクリーンショットが暴露され始めると、「どうやら本当にアイテム増殖バグがあるらしいぞ」ということがわかってきました。私は当初、高度なハッカーの類がパケットを改ざんして攻撃しているのだと推測していたのですが、一週間もしたころでしょうか、突然公式Forumにアイテム増殖の具体的な方法が書き込まれ、一同が唖然となります。

その方法とは・・・


1. 個人間トレードを開始する。

2. 渡す側は、増殖したいアイテムを相手に渡すようにして、Confirmボタンを押す。

3. 受け取る側は、増殖したいアイテムがトレードに乗ったのを確認したら、意図的に通信を遮断する。

4. 受け取る側は、Confirmボタンを押す。

5. しばらく待ってから、渡す側がCancelボタンを押して、取引を中断する。

6. 中断されたのを確認してから、受け取る側は、通信を復旧する。

7. 双方がアイテムを持った状態になる。

 

そう、トレード中に、通信を止めるだけ。

たったのこれだけでアイテムが増殖できてしまうのです。


まさか21世紀も1/5以上が終わった現代において「サーバーを一切介さないでトレードが成立するMMORPG」をあのAmazonの名を冠するゲーム会社がリリースする日が来ようなどとは一体全体誰が予想し得たでしょうか。


結果、サーバー全土に渡る経済封鎖が行われ、個人間トレード、交易所、ギルドバンクの利用などあらゆる富の移動が不可能にされたのですが、現実世界だけではなくゲーム内でも経済活動の制限が行われる日が来るとは実に皮肉なものです。

しかも、問題はこれだけに留まりませんでした。ゲームをWindowedモードで起動し、戦闘中にゲーム画面のWindowを激しく動かしまくって意図的にクライアントサイドでの処理を止めると、なんと完全無敵になるというバグが発見されたのです。全く理解できません。


まさか21世紀も1/5以上が終わった現代において「クライアントサイドの処理を止めると一切ダメージを受けなくなるMMORPG」をあのAmazonの名を冠するゲーム会社がリリースする日が来ようなどとは一体全体誰が予想し得たでしょうか。


あまりの事態に、とうとう開発者たちも重い腰を上げて火消し文章を書きます。

https://forums.newworld.com/t/dev-blog-update-on-current-issues/504297/1

それによると、本作は「To be very clear, New World is not client authoritative — from a simulation standpoint, New World is entirely server based」などと主張されていましたが、誰もこのような世迷い言を信じる者はいませんでした。クライアントサイドでの入力によってサーバーサイドの挙動が不正に変化してしまうのであれば、それは入力に対するValidationが何ら行われていないということであり、Server-Based Authoritativeなアプリケーションとは言えません。この声明発表は単に開発者たちが自らの無能を晒しただけに終わりました。


数日後。

アップデートによりアイテム増殖も無敵化も修正され、経済封鎖も解除され、事態は沈静化するかのように思われました・・・

が、今度は家具を無限に増殖させるバグが発見されました。

その方法とは・・・


1. 家のデコレーションを開始する。

2. 増殖したいアイテムを家に配置する。

3. 増殖したいアイテムが家に配置されたら、意図的に通信を遮断する。

4. しばらく待ってから、Cancelボタンを押して、家具配置をキャンセルする。

5. 中断されたのを確認してから、通信を復旧する。

6. アイテムが家に配置された状態のまま、手元にも残る。


お気づきかと思いますが、前回と全く同じ手順です、彼らは何も学んでいません。

あの日本を代表するみずほ銀行ですらこんなデタラメな修正はしないのでは無いでしょうか。こちらの問題も2回目の経済封鎖の後、現在では修正されているのですが、2回も同じ手口で成功したのですから、今でも似たような手口によるアイテム増殖が可能なのではないかという噂がコミュニティ内で絶えません。もはや完全な無法地帯です。


他にも、チャット欄にHTMLタグが使えてしまうバグだとか、

チャット欄のHTMLタグを利用してリンクをmouseoverした瞬間に攻撃するコードを仕込むバグだとか(onmouseoverが動作してしまうらしい)

全く、話題に事欠かないゲームです。


さて、ここまでお読みいただいたエンジニア諸兄の中にはお気づきの方もいらっしゃることかと思いますが、このNew Worldというゲーム、根幹がそもそもMMORPGとして動作するように設計されていない可能性が極めて高いです。実際、企画の初期段階では、MMOではなく、MOのPvPゲーム(ゲームに詳しい方ならRustといえばご存知でしょうか)として作られていたという噂があります。そのため中央のサーバーが全ての処理を解する設計になっていないのでしょう。現在のNew Worldは単に我々が動作させているクライアントと全く同じものをHeadlessモードでサーバー側で動作させ、その処理を真とするような実装になっているだけなのではないか、と私は勝手に推測していますが、あくまで推測の域を出ません。

ここでの学びは、根幹がそもそも間違っているシステムは、後から何をやっても救えないということです。

くれぐれも皆様もご用心を。


bot、その進化の軌跡

もう一つ、本作New Worldの世界で技術的に興味深い話題があります。それはBotです。MMORPG界隈においてBotという単語を使った場合、それは「プログラムで自動的にキャラクターを操作し、何らかの行動を行わせ続ける」行為を指し、全世界に存在するほぼすべてのMMORPGのエンドユーザーライセンス契約条項において禁止されています。禁止されている理由は多々ありますが、基本的にMMORPGというのは単一の行為をひたすら尋常ではない回数と時間に渡って繰り返しまくることで資源やアイテムやお金や経験値といったリソースを収集して強くなるのが目的ですから、当然自動化と相性がいい・・・失礼、自動化すると真面目に刺し身たんぽぽをポチポチやってる人間が不利益を被るわけです。そういったわけで禁止されているんですね。

まぁ、禁止されてるってことは、当然やる人間が居るわけです。本作New Worldにおいても全く例外ではないのですが、ただでさえバグだらけでマトモな入力検証すら行っていないゲームであることがすでに露呈しているわけですから、今や世界中のBot職人の格好の的となり、過去のゲームで見られた単純なBotとは比較にならないほど洗練されたBotの数々が世界の至るところで観察されるようになったのです。

そのいくつかをご紹介しましょう。


バージョン1.0: Fishing Bot


最初期からいるBotです。多分ゲーム開始2週間後にはもう大量発生していたと思います。名前の通り、自動的に釣りを行うBotとなっています。釣りは一定の位置から動く必要もなく、ただひたすらマウスをタイミングよくクリックするだけで無限に実行できますから、大変自動化しやすいんですね。おまけに本作の釣りは針を垂らした瞬間に針にかかった魚の種類がサーバからクライアントに送信されるというキ○○○・・・失礼、少々脳細胞が足りていない実装になっておりまして、そのためパケットをキャプチャすることで目的の魚が針にかかるまで即座にリセットを繰り返すという大変効率の良い機能まで兼ね備えております。

ちなみにこのBot、2021/12/01現在でも対策されておらず、世界中どこでも見ることができます。


バージョン1.1: Mining/Logging Bot

次に現れたのがこちら。鉱石を自動で掘ったり、リソースを自動で採集したりしてくれるBotです。本作の鉱石やリソースは毎回全く同じ座標に再生するため、同じ座標まで歩いていってボタンを押すだけで自動化できちゃうんですね。とはいえ、先に他の人が採掘していたり、リソースが存在しなかった場合にどうするか、とか、移動が邪魔された場合に対応する必要があるとかで、単純な釣りBotよりは遥かに実装難易度が高いようで、私がプレイしてたサーバーではなかなか見かけませんでした。


バージョン2.0: Questing Bot

https://www.reddit.com/r/newworldgame/comments/qhck8d/complex_scripted_questing_bots_already_available/

YouTubeに動画が見つからなかったのでRedditから引用してきたのですが、必見です。とうとう彼らBotは釣りや採集といった単純動作だけではなく、戦闘とクエストを自動でこなせるように進化してしまったのです。何十体ものBotが蟻の行列のように規則正しく動いて規則正しくクエスト目標の敵をしばき倒す姿は戦慄さえ覚えますが、AIだとかRPAだとかの波はこんなゲーム内にも訪れてきているわけですね。


バージョン3.0: PvP Bot

2週間ほど前ぐらいに発見された最新のBotです。これは噂レベルでしか聞いたことがないので真偽不明ですが、とうとうこの最新のBotはPvP (Player vs Player:対人戦) クエストを自動でこなせるようになったとのこと。といってもBotが我々人間相手に斬りかかってくるわけではなく、対人戦モードを有効にした状態で敵の基地に忍び込んでアイテムを手に入れて帰ってくる、みたいなお使いクエストでしかありません。ただのゾンビですから発見さえすれば簡単に始末できるのですが、問題はこれらが自動化されていて24時間365日常に動き続けているという点にあります。我々人間には休息が必要ですが、彼らは一瞬一秒たりとも休むこと無く、何度殺されても諦めること無く、ひたすら目標めがけて突進してくるのです。これにはどれほど優れた人間も太刀打ちすることが出来ません。これはゲームの中のお遊びですから笑い話ですが、現実世界の戦争がこのように無人の自動兵器がひたすら突撃を繰り返してくる世界になってしまったらと思うと、薄ら寒い思いがしますね。


ちなみにですが、今しかたgithubをちょっと調べてみたところ、golangで書かれたNew World向けのBotのソースコードが転がっていたりしましたので、ちょっと探せば皆様も簡単にBotを運用できるかと思いますが、決して真似しないでくださいね。


まとめ

なかなか得られない機会かもしれませんが、もし読者の皆様におかれまして、MMORPGを開発するという案件に参画するご縁がお在りになりましたら、その際は是非本記事の内容をご参考にしていただければ幸いです。


#pyspa Advent Calendar 2021 - 1日目


2020年12月1日火曜日

マネージメントに必要なことは全てゲームから学んだ

この投稿は毎年恒例、pyspa Advent Calendar 2020の1日目の投稿になります。

どうもご無沙汰しております、akisuteです。すっかり年に1回アドベントカレンダーのときにだけ顔を見せる人になっておりますが、おかげさまで無事平穏に過ごしております。


さて突然ですが私はプログラマーを引退しました。


なぜなら今年で36歳だからです。プログラマーは35歳になったら定年ですね。

実際のところ、このぐらいの年になると、よほど何らかの意志が働かない限り、技術に対する情熱みたいなものが失われてくると思います。もちろん本当に技術とプログラミングが好きな人は間違いなく35歳なんかで情熱を失ったりはしないと断言しますが、残念ながら私はそうではなく、もはやiPhoneには大した興味が湧いておりませんし、最近はJavaだのGoだのTypescriptだのVue.jsだのといったものを必要に応じて細々と書いている程度に過ぎません。

さてプログラマーを引退してどうしたかといいますと、マネージャーになりました。といっても、正確にはマネージャーなんてエラソーな立場ではありません。スクラムチームのリーダーといった程度の役割です。昔っぽく言えば、係長でもないので、班長ぐらいでしょうか。上長の人からお前にならできると思うからぜひやってくれとお願いされて引き受けることにしました。ついでにお給料もちょっと増やしてもらったので満足です。このままモチベの上がらない技術者を続けるよりは未来もあるでしょう。

とはいえ、問題点もあります。なにせ、私は基本的に人間が大嫌いです。可能であれば常に一人でいるほうが嬉しいと言うのに、何が楽しくて他人のマネージメントなんてしなければならないのでしょうか。実は私の上長には人を見る目が無いんじゃないでしょうか。さらに、そもそも私は生まれてこの方マネージメントに関する勉強も教育も一切受けたことがございません。ズブのド素人にプログラマができないのと同じことで、全くの未経験者がマネージャなんてできるわけがないでしょう。

まぁ、それでもいいや、別に会社の業績がどうなろうが知ったことではないし、お給料くれるというならやってやろうじゃないかと思って一念発起、できるかどうかわからないまま快く引き受けてしまったのですが、いざやってみたら案外マネージメント業務ができちゃったので、今日は今年一年のマネージメント体験で得られたことをつらつら書いてみようかと思っております。


マネージメント業務を行う人間に必要な適正

古今東西、何の仕事でもそうなんですが、仕事には適正というやつがあります。

まず能力面での適正というやつは以下の通りだと思っています。

  • 論理的思考が人並み程度に可能
  • 人前でしゃべることができる
  • 恥ずかしがったり躊躇したりしない、慌てず騒がず堂々としている

たったのこれだけです。

次に考え方、思考面での適正というやつは以下の通りだと思っています。

  • 目的を達成するのが楽しいと思える
  • エンジニアの苦痛を理解できる、プログラマやエンジニアが何をされたら嬉しくて何をされたらクソムカつくかを心の底から共感できる
  • ボスとリーダーの違いを理解しており、ボスではなくリーダーになろうという意思がある
  • 一方で自らがチームで最も価値のない人間であるということを自覚することができる・・・マネージャーは別に何も生産しません。生産価値ゼロです。単に生産価値を生み出している他のチームメンバーの雑用奴隷をしているだけです。自分のほうが上だとか勘違いするのは思い上がりも甚だしいです。したがって成功は全てメンバーのおかげであり、失敗は自分が無能な判断をしたためか、サボったから、と考えるのが当然だと言えます。

この程度の要素があれば基本的に誰でもマネージメント業務は可能だと思います。別に人間が好きとか嫌いとかは必要な要素ではありません。もちろん、人によって方法論が異なるとは思いますが、少なくとも私にとっては必要ありませんでした。


マネージメントはゲームである

はい、ゲーム脳の私の考えることですが、マネージメントはゲームです。ゲーム機やコンピュータやゲーム盤を使うのか、現実世界で行うのかの違い程度しかありません。そもそもゲームというのは基本的にマネージメントそのものです。シムシティのようなゲームだってマネージメントですし、エイジオブエンパイアスタークラフトといったゲームもマネージメントですし、アクション要素以外のほぼすべての要素はマネージメントであると言えます。それどころか最近はチームで対戦するバトルロワイヤル系のゲームや対戦ゲームが増えてきました。これらのゲームで味方同士が協力して相手に打ち勝つというのはチームメイトのマネージメントそのものであると言えます。すなわち、ゲームをしている人なら、誰でも毎日マネージメントを実践していると言えるのではないでしょうか。


最低限の定石を覚える

古今東西いかなるゲームにも定石という概念は存在します。古くは将棋囲碁チェスにも存在しますし、リアルタイムストラテジーゲームでしたら初期オーダーと言う概念が存在しますし(HCCC→農民掴んで豚に送りつつ家1件建設・・・)最近流行りのバトルロワイヤルでも初手どこに降下するのが良いとか、どの武器が強いとか、何を確保すれば有利だとか、何のゲームにも必ず定石と呼ばれている概念が存在するわけです。

上達したいなら何のゲームでも必ず定石を学ばなければなりません。定石に当てはまらない動きができるのは定石を知っているからです。したがって、マネージメントもゲームですから、定石を学ぶ必要があります。

マネージメントにおける定石とは何かという話ですが、ありがたいことに世の中にはマネージメント論みたいな話があって、特にソフトウェアエンジニアリングのような知的労働をするチームをマネージメントするみたいな方法論だけでも沢山存在します。私の場合はスクラムという方法を学びました。まぁ、会社がカネ出してくれたので、専門の講座を受けに行っただけなのですが、おかげさまで最低限の定石は得られた気がしています。それにスクラムの元となっている経験主義という考え方は、答えのない決断を迫られることが多いマネージャーにとって必要不可欠な考え方ではないかと思いますし。


マネージメントという仕事はどういうゲームか考える

他の現実世界の事象と全て同じなのですが、ゲームと違い現実世界には明示的なクリア条件・達成条件・ゴールといったものがありません。またゲームと違いパラメータが明示的ではありません。全てのゲームは(アクションゲームですら)基本的に数字やフラグと行ったパラメータを適切に操作してゴールを達成するものですから、それらパラメータとゴールを適切に自分で設定してやる必要があります。


マネージメントのゴールを理解する

これは基本的に組織のゴールを達成することとほぼ等価になると思います。それとは別に、マネージメントに登場するパラメータの値をうまく調整してチームが破綻しないようにするというのも大事なゴールになります。すなわちパラメータを維持調整促進しつつ組織のゴールを達成するのを狙うことになるでしょう。

厄介なのは組織のゴールというやつが現実世界ではしばしば達成不可能な世迷い言だったり、達成するためにはチームメンバーやパラメータを犠牲にしなければならないようなものだったりする点です。そのため、現実世界においては俗に「調整」と呼ばれる、組織のゴールを達成するフリを上には見せつつ、自らの中では差し支えないゴールに置き換えておき、上に対してはフィルターを通して進捗を返すみたいな作法が必要になってきたりしますが、お察しの通り、そのような作法が必要な地点で大体何かが間違っています。人間のやることですから何かが間違うのは仕方のないことなのですが、せめて自らのチームの中ではそのような間違いと調整が起きないように最大限尽力するべきでしょう。


マネージメントするパラメータを理解する

というわけで次はパラメータを定義します。私が定義しているチームマネージメントのパラメータは以下のとおりです。
  • 士気
  • リスペクト
  • 発言力

これだけです。順番に見ていきます。


士気

極めて重要な値で、端的にいえばやる気です。他のゲームに例えるならライフポイントやヒットポイントとバフ・デバフ係数の両方を兼ねている最重要値です。この値を減らしたらゲームオーバーだと思ってください。あらゆる手段を用いて高める必要があります。Hearts of Ironという有名な第二次世界大戦シミュレーターゲームがあるのですが、あのゲームで戦闘が敗北するのは部隊の兵士が死ぬからではなく、士気がゼロになるからです。人はそうそうかんたんには死にませんが、やる気が無くなると死んだも同然の状態になります。そしてやる気はいともたやすく無くなります。

士気を上げる方法、下がってしまう要因などはいくつもあると思いますが、あまりにもたくさんありすぎるのと、余りにも重要な概念ゆえ、後ほど場を設けて述べさせていただきます。


リスペクト

GTAとかRed Dead RedemptionとかFalloutとか、そういう洋物のゲームによく出てくる概念ですが、日本語化が難しいのでそのままリスペクトとします。これは何かというと「アイツすげえな」「アイツは便利なやつだ、俺にとって使える」「アイツは有能だ」などといった他人からの正の評価を表す概念です。

あなたも自分の身の回りにリスペクトがある人が一人ぐらいはいるのではないでしょうか。そして想像してほしいのですが、そういうリスペクトがある人物からお願いされたり依頼されたことと、道端の他人にお願いされたり依頼されたこと、どちらのほうを聞いてあげたくなる、頼まれたくなるでしょうか。考えるまでもありませんね。

そう。マネージメントを行う上で極めて大事な要素です。コンピューターゲームの世界ではユニットを選択して右クリックしたら文句も言わずにその通りに動いてくれるものなのですが、現実世界ではそのような魔法は発生しません。あなたがお願いする内容が、あなた自身のリスペクトと比較して十分であれば、高い確率で(絶対ではなく確率で!)聞いてもらえるものなのだ、というふうに理解してください。したがってより無茶苦茶な内容を聞いてもらいたいのであれば、あなた自身にとんでもない量のリスペクトが必要になります。もし、リスペクトがない人物の依頼や命令が通っているのであれば、それは全く自然な状態ではなく、「上司の命令だから」「金をもらえるから」とかそういう別の動機によって発生している状態になります。これは極めてチームの運営上危険な状態であり、どんどんと歪みを生み出し最後には爆発してチーム自体が消し飛ぶことになります。

健全なチームは、上司の命令だからでもなければ、金をもらえるからでもなく、依頼を受けた側が自主的に自分もそうしたいと思っているから依頼を受けるか、または依頼主に十分なリスペクトがあるから成り立っているのです。

そんな大事なリスペクトですが、これは他人からの相対的な評価ですので、評価する側が何を大事にして何を大事にしないかによっても高め方が変わってきます。例えば評価する側の人が技術を最も大事にするタイプの人間であれば、その人からのリスペクトを高める方法は自分自身の技術力を高める以外にありません。逆に評価する人が人間性を求めている人なのであれば、あなた自身に人間的な魅力、ユーモアがあるとか、明るい性格をしているとか、そういう方法が必要になります。

ですがもっと簡単にリスペクトを高める方法があります。ゲームと同じです。他人のお願いを聞いてあげるだけです。どんなに簡単な内容でも構いませんから、対価を求めず相手のお願いをすべて聞いてあげてください。失敗しないようにね。すると「アイツは自分のお願いしたことを色々きちんとこなしてくれたいいやつだな」と思ってもらえるものです。私はもはや技術力がないアラフォーですから、チームのために様々な雑用をこなしてエンジニアの苦痛を取り除くことでリスペクトを稼ぐしかありません。


発言力

遥か大昔に初めてガンパレード・マーチというゲームをプレイしたときに度肝を抜かれたのがこの発言力というパラメータでした。要するにお金のようなもので、対人関係で他人にお願いをしたり、会議で発言する際に必要となり、勲章をもらったりすると増えます。当時はガンパレの独特で斬新すぎる仕組みを上手く理解できなかったり、最強の武器(NEP)を手に入れるための方法がカネで買うでも敵からのドロップでもなく発言力で取り寄せるという内容に正直何だこれはと思ったものなのですが、今なら言えます、このガンパレード・マーチというゲームほど対人関係や発言力の概念を上手く取り入れているゲームは今に至るまで他に存在しません。

発言力はリスペクトと直結しています。リスペクトの値が高ければ高いほど発言力は大きく生産されるようになり、自分の意見を通しやすくなりますが、発言力を浪費した結果成果が上がらなかったりすると、リスペクトが減少し、さらに発言が難しくなるという負の循環に陥ってしまいます。

ちょっとわかりにくいかも知れないので具体例を挙げますが、あなたの身の回りにいらっしゃるクソ無能認定している人間を一人思い浮かべて、そいつがエラそうに自分の参加する会議で何かクソ無能っぽい頓珍漢な世迷い言を発言しているさまを思い浮かべてみてください。どうでしょうか。口を閉ざして視界から失せろと思うに違いありません。そうして自分の士気が下がります。これが、リスペクトのない人間が、発言力を無駄遣いしてさらにリスペクトを落とし、他人の士気を落としてチーム全体にダメージを与える状態です。こういう状態を避ける必要があるわけです。簡単ですね。

発言力は基本的に何でも発言・・・すなわち自らの意思を表明すれば減り、発言しなければ自らのリスペクトに相当する値まで自動的に回復するようなものなのですが、面白いのは発言によってリスペクトを得ているタイプの人間が余りにも発言しなさすぎると価値がない人間だと思われてリスペクトが減少し結果として発言力も低下するとか、逆に十分なリスペクトがある人間が発言すると発言することによってさらにリスペクトが高まる結果話せば話すほど発言力が増えていくとか、ポジティブフィードバックを受けやすいパラメータに思えます。

増やす方法はリスペクトを増やすことですが、減ってきたときには不用意な発言を厳に慎み、ここぞという場面でのみ最も適切な意見を述べ、メンバーの信頼を再び勝ち取る必要があるでしょう。

エンジニアでよくあるのが、どれほどリスペクトのある技術力のある人でも、発言すれば発言するほど発言力は消費されてしまうということです。つまり、どれほどのド正論だったとしても、ああでもない、こうでもない、それは間違っているからこうしろ、と言い続けると発言力が低下してしまい、結果として本当に大事な場面で反対に合ってしまうことが往々にして発生します。残念ながら人類というのは完全に論理的な生き物ではなく、どれほどの正論でも、どれほど理論的に正しいことでも、自分がムカつくこと=すなわち相手ばかりが正論を発言して結果を得続けるという状況には容易に賛成してくれません。時には如何に相手が間違っていてもあえて無視し、自らの発言力を維持しより大事に備える必要がある、というケースも存在すると思っています。


チームメンバーの自主性の話

よくチームメンバーの自主性を重んじるとかなんとかそういう話がマネージメント論に登場してくると思います。ですが私に言わせれば「重んじる」なんてのはチャンチャラおかしい話で、まるでマネージャーの言うことに全てメンバーが同調して従い、たまに自主性のあることを言うからそれを聞いてあげるんだ、みたいなノリに聞こえます。

大間違いで、実際にはチームメンバーには自主性しかありません。すなわち、基本的には、自分のやりたいことを、やりたい通りにしかしません。マネージャーの話なんて聞いてくれるわけがない、というのが当然かつ自然な状態です。これは自虐でも何でも無く事実です。嘘だと思うなら今すぐLeague of LegendValorantといったチーム型対戦ゲームをインストールして、野良のランクマッチに入って、周りのみんなにああしろこうしろと命令してみては如何でしょうか、誰も話を聞いてくれませんので。

現実の仕事の場でこのような間違ったことがまかり通るのは、マネージャーという肩書があるから、上司という肩書があるから、または彼らが金をもらって仕事をしているからであって、それらの要素がなければ命令という概念は一切成り立ちません。

したがってまず私がチームで仕事をする際に考えるのは、大変逆説的なのですが、全て自力でなんとかするということです。なぜならチームメンバーは自分のやりたいことをやりたいようにしかしないのであって、私が何をしたいか、チームが何をしなければならないか、案件のゴールが何でそのためには何を達成しなければならないかなんて知ったこっちゃないというのが全く自然な状態であるためです。

しかしながら誰が考えても分かる通り、これでは仕事になりません。私一人でできることは何もありません。技術力も若いのに劣りますし、作業量も作業速度も劣ります。したがって目的を達成するには、勝利するためには、メンバーに協力してもらわなければならないのです。

そこで、先程書いたリスペクトの話が大事になってきます。まずはメンバーにあなた自身が彼らにとって有益で使える存在であるということを認識してもらわなければなりません。彼ら自身とて目的を持ってチームに存在しています、それはチームに与えられたゴールを達成したい、と少しぐらいは思っているからそのチームに居るわけです。ゲームなら勝ちたいであるし、仕事ならプロジェクトを成功させたいでも、コード書きたいでもなんでもいいです、とにかくそういうことです。その彼ら自身の目的をマネージャーたる者が手助けすることができる、という認識を持ってもらうところからが大事になります。


メンバーに自主性の範囲で何ができるのかを把握する

再びLoLの例になって恐縮ですが、例えばチームメンバーといっても彼ら自身の能力は一人一人異なってきます。例えばボトムレーンでラストヒットを取る程度なら何一つ指図しなくても自力でできるが、ジャングラーがGankに来ているのを自力で把握できないとか、敵のローテーションタイミングを把握できてないとか、正面のエズ君のスキルショットを回避できないとか。そのようなプレイヤーを完全に放任してボトムレーンを任せたらどうなるでしょうか?言うまでもありませんがズタボロに負けますし、結果対面のエズ君がクソ育ってクソ無双して我々はボッコボコにされて敗北して目的を達成できず最悪な気分になること間違いなしでしょう。

このような与えられた仕事を達成するのに必要なスキルを自主性を持って発揮できないようなケースの場合は、自主性を持って達成できる範囲のみ、すなわちラストヒットを取らせるところまでは完全に放任し、Gank警告は全てこちらが指示、逃げ方も全て指示、スキルショットは回避してくれないから代わりに全部自らが受けて盾になる(その結果自分が最悪死ぬかも知れないがそれは知らん)、というようなケアが必要になってきます。

逆に運良く自らのチームメンバーの中にブロンズ5のフリをしたプラチナダイヤプレイヤーが混じっており、彼らは自らの判断で一人で敵ジャングルを荒らし回ったり、Gankに行ったり、ドラゴンを支配したり、視界を取ったりといった極めて高度な判断と実行をこなすことができる場合もあります。またそこまで有能でなかったとしても、集団戦でUltを3人にぶち当てることに関しては右に出る者がない、みたいな一芸に秀でた人もいるかもしれません。

そのような幸運なケースの場合は彼らの自主性を重んじ、基本的に彼らの方針をリスペクトして受け入れ従ったほうが良いです。たとえそれが自らの経験と食い違ったり、明らかに間違っていそうだったとしても、まず彼らに自主性を発揮してもらうべきです。その代わり、彼らのために視界を取ってやるとか、ヒールを使ってやるとか、そういうサポートに徹してあげ、そして万一彼らが失敗しても非難するようなことをしてはなりません。そうすれば彼らからしてみれば、「あいつは俺のやりたいことをやりたいように任せてくれるし、面倒事は全部引き受けてくれるし、一緒にチームを組んでいてやりやすいな」と思ってもらえるわけです。こういう状態になれば自らがミスした場合に「全て任せてもらったのに失敗してしまったから申し訳ないな」「たしかにさっきは俺のミスだった」「次はアイツの話を聞いてやるか」という具合に心を開いてもらいやすい。

もちろん中には全て他人のせいにするクズもいますが、基本的にそのような人間と一緒に何かゴールを達成するのは不可能ですので、自己反省ができない人間に自主性を与える必要はないし、もっと言うなら同じチームに置いておく必要もないでしょう。コマとして切り捨てるのが良いと思います。先述のスタンスを採用していれば自然とそのようなクズが炙り出されますから、その点でも一石二鳥と言えます。ですから大事なことは、自分が見てアイツは出来る!と思ったチームメイトに関して言えば、全て任せて彼らの言うことを受け入れ、自分は支援してあげる、というスタンスをとることです。まず自分が相手をリスペクトするってことですね。そうすれば彼らから自分へのリスペクトも得られてお互いが得をすることになります。


チームの士気の話

先程チームの士気を高い状態で維持するのが極めて大事だと書きましたが、では具体的にどうすればよいのだろうか、という話をちょっと残しておきます。

私はチーム運営にはノリすなわち本能的な要素と、理性的で計画的な要素の両方が絶対に必要だと思っています。なぜならチームメンバーは人間であり、人間である以上本能的な好みを見逃すことはできないからです。しかしながらチームメンバーは目的を達成するために集まっているものですから、目的を達成するためには理論と計画が絶対に不可欠です。ノリだけでは何も達成できない大学のサークルになってしまいますし、理論だけでは士気の維持ができなくなるでしょう。

良い例えとしてRimworldの例を挙げたいと思います。Rimworldの世界において最も儲かる商売は何でしょうか、といいますと、臓器売買です。なにせ何もしないでも海賊やならず者、隣の蛮族どもが自分たちの街に武器持って大挙して押し寄せてくるわけですから、それを撃退し、息のあるものを牢屋に閉じ込めて、一人ずつ眼球・両手両足・胃腸・肝臓・腎臓・肺を取り除いてから心臓まで取って殺し、生皮を剥いで衣類にし、肉は家畜の餌に混ぜるなりすりつぶしてペーストにしてしまえばいいのです。材料代はタダ、墓場を掘る手間すら省けますし、臓器は非常にいい値段で売れます。人体解剖は医者のスキル上げにも役立ちます。これが理論的にはどう考えても最適解でしょう。ですがこのようなことをすると住人たちに凄まじい勢いで「捕虜を殺した」「捕虜の臓器を売り物にした」「人間を解体した」「人皮の服を着た」「人肉を食べた」といった感情デバフがついてしまい、あっというまに住人たちは精神崩壊を起こして街はめちゃくちゃになってしまいます。すなわち、理論的に最適だったとしても、人間の本能が耐えられないということを表していると思います。ちなみにRimworldにおいてはサイコパスという特性を持った人間がおり、サイコパスの人間であれば捕虜をどれだけ殺そうがバラバラにしようが臓器を取り除こうが一切の感情デバフを受けることがありません。すなわち現実世界のチームビルディングにおいてもサイコパスだけでチームを構成すればここで私が申しているような本能と理論のバランスを取るなんてことは不要でただひたすら理論最適解を追い求めることができるかと思いますが、現実味がないためここでは却下させていただきます。

さてここまで書いて何が申し上げたいかということなのですが、すなわちチームを運営するマネージャーたる者は、本能的な好みと理性的な計画の両方をチームメンバーに提供できなければならないということです。そうしなければチームの士気を上手く維持することはできないでしょう。理性的な計画の方に関してはまぁ私なんかより技術力があったりマネジメント論やチームビルディングをきちんと学んでいる皆様方のほうが得意でしょうから、それは置いておいて、ここではいくつか本能的な好みの話をしたいと思います。


別にノリを高めるために飲み会をする必要はない

まず最初に申し上げたいことです酒が嫌いな人も居ます。時間を拘束されるのが嫌な人も居ます。飯を食うことに執着がない人も居ます。完全に昭和の考えです。忘れましょう。そもそも私自身が体育会系のノリは嫌いですし、エンジニアでそういうノリが好きな人は少ないと私は思っていますから。もちろん、そういうのが好きな人だけが集まっているチームなら、思う存分やればよろしい。


チームメンバーに安心感を提供してあげる

私が推奨するのはこういう方法です。「安心感」というのは人間の本能の極めて根深いところに存在するものです。したがってメンバーは安心を求めます。こいつに任せておけば安心、こいつが間に立ってくれれば面倒な仕様は俺のところに降りてこないから安心、こいつがレビューしてくれればトラブルが起きない、こいつが起てるアイディアはだいたいうまくいくから楽ちん、そういったものです。


安心感と自主性の二律背反

人間は「考えること」「決定すること」に苦痛を覚えるようにできています。すなわち思考を放棄し、誰かに最適解を決めてもらえることができれば、これ以上無いほどの安心感と幸福に包まれるようになっているのです。

何を馬鹿げたことをとんでもない!と怒られるのは当然ですが、ですが考えてみてください、これまでにただの一度も今日の晩御飯を何にするか悩んだことはないでしょうか?転職先をどこにするか悩んだことは?iPhone 12を買うかiPhone 12 Proにするか悩んだことは?必ずあるはずです。基本的に、決定というのは、苦痛なのです。したがってこれを取り除いてあげるというのは極めてメンバーの士気を高めます。

しかしまるでそう言うと洗脳みたいに思われるかも知れません。実際そのとおりで、そもそも我々人間は考えるからこそ価値を生み出せるのであり、考えるからこそ成長するのです。全て決定して決めてしまうなどというのはありえないことですし、そもそも相手がそれを受け入れてくれるとも考えられません。

すなわち、メンバーに進んで考えてもらうべきものは、設計やアーキテクチャなどといった成果・成長に結びつく挑戦的にで面白い分野であり、逆に考えさせないほうがよいものは、「自転車置き場の屋根の色」的などうでもいい些細な問題、ないし正解のない決定などがあるでしょう。明日のミーティングの開催時間なんて時間帯が抑えられれば15時開始でも16時開始でも問題ありませんからマネージャーがさっさと決めて取ってしまえばいいのです。どっちがいい?なんて聞くだけ時間と思考の無駄です。それとかTrelloボードのタグの色なんてどっちが赤でどっちが黄色だろうが知ったこっちゃないでしょう。そういうのもちゃっちゃとあなたのセンスで決めてしまってください。苦手ならそういうのが好きな人に頼んでもいいです。

同様に、メンバーに対してお願いをするときは相手に考える余地や推測する余地を与えないぐらい些細に至るまで完璧に支持することを目指してください。間違っても主語や目的語を省略して話さないように。メンバーがそこを考えなければならないのは苦痛でしかありませんし、その結果マネージャー側の想定する結果と異なる解釈をしては悲劇です。メンバーの苦痛を取り除くための努力を惜しんではなりません。


アットホーム感とか人間味を出す

Trelloボードのタグの色の話が出たのでついでに書いてしまいますが、例えばTrelloボードの背景写真に何を選ぶかであなた自身のセンスや個性、人間味といった本能に訴えかけることができます。毎週毎週きれいな自然の写真を探してきてもいいですし、今週末行った観光地の写真でもいいですし、そういう一見どうでもいいけど人間味を感じる要素を大事にするというのが一つ有効なのではないかと思っています。私どものチームの例をあげますと、毎週のスプリントに名前をつけてみたりとか、スプリントレトロスペクティブの際にスプリント名に即したトリビアを用意するとか、そういうことをやっています。例えば11月16日~11月20日のスプリント名は「ウィリアム・テル」でした。11月18日が息子の頭のりんごを射抜いた日だから、とかそういう理由なのですが、そこから転じてその週のトリビアは運動会のときに流れる曲はウィリアム・テル序曲と言う、とか。私は知りませんでした。ちょっと面白いですよね。こういう人間味のある活動というのが大事なんじゃないのかなと。人間嫌いな私が言うのもどうかと思いますが。


会議での細かいテクニックあれこれの話

ここでは私が普段から気をつけている細かいテクの話をつらつら書いておこうかと思います。全て可能な限り明日からすぐに使えるテクとしたつもりでございます。


会議のゴールは何か

マネージメントというゲームのルールとほぼ一致しますが、会議の場合は以下の優先順位のとおりに実現させます。

  1. 会議自体のゴールを達成する。すなわち、何かを決定するだとか、結論を出すだとか、具体的なアクションを生み出す。失敗するとチームの士気が下がり、場合によってはあなたへのリスペクトが減ります。
  2. 士気を最大に稼ぐ。士気の低下は即ゲームオーバーです。絶対に避けてください。
  3. リスペクトを可能な限り稼ぐ。最悪減らないようにする。
  4. 発言力の消費を最小にする、できればプラスにする。まぁ、発言してゴールを導かなければならないので、多かれ少なかれ発言力は使います。プラスになったら御の字ですが、他のところで貯めましょう。


激流に身を任せ同化する

要するに「空気を読め」「流れを読め」というやつです。ほら来ましたよ、全エンジニアがクソ喰らえと思っている単語。クウキヲヨメ。私だって大嫌いですよ、そりゃ。しかし、事実です。空気を読むのは日本人だけだとか思っているあなた、それは嘘です。韓国人も中国人もベトナム人もアメリカ人もスペイン人もドイツ人もブラジル人も全世界共通で彼らは空気を読みます。ただし程度が違う、性質が違うだけです。残念ながら人と人が話を持つ上で空気を読む、流れを読むというのは極めて大事な要素と言わざるを得ません。
とはいえ実は簡単です。単にこう覚えておきましょう、「自分より発言したがる人間がいる場合は聞き役・守勢に周り、補助を行い、一人が独壇場を作らないように調整を行う」「自分より発言したがる人間が居ない場合は自分が喋り役・攻勢に周り、議論の流れを作り、たたき台を作って周りから発言を引き出す」、これだけです。柔道とかと同じですね。相手が前に出たら下がり、後ろに下がったら前に出る。そうすればお互いがぶつかることがなく、無駄に衝突することもなければ、お互いから何の発言も出なくなって手詰まりになることもありません。基本的にはこのように現在自分が攻勢に出て引っ張るべきか、守勢に入って気を伺うべきか、だけを判断すれば良いと思います。お互いの意見が意味もなく衝突すると敵対心が生まれる危険性があり、何も意見が出ないとチーム全体の士気が劇的に下がります。どちらも避けなければなりません。


流れを止めない

まずは自らが喋り役・攻勢に回る際の細かいテクからいくつかご紹介します。

会議において最も避けたいのは沈黙です。全員が考え込んでいる、というのは正しい状態にも思えますが、大抵の場合は考え込んでいるフリをしているだけで全員が混乱しているだけか、発言したいのだがためらっている状態かのどちらかです。この状態は時間の無駄であり、士気の低下を招きます。自らが喋り役に回っている際にはこの自体を絶対に避ける必要があり、逆に他人が喋り役に回っている際に沈黙が訪れたらこのときこそが発言のチャンスです。

私個人的には、5秒間の沈黙が発生したら必ず何か発言します。そのときによく使うテクニックが以下のものになります。


自ら殴られにいく、自らがたたき台となる

一番有用で且つ私がよく使うのがこれです。どんなデタラメなアイディアでも構わないから思いつきを出します。大事なのは、周りの誰かに「そりゃダメだろ」と突っ込んでもらうことです。最悪、デタラメなアイディアに決まってしまうよりも、なにも決まらないよりは圧倒的にマシです。その場合、デタラメなアイディアがうまくいくこともありますし、それが失敗したなら失敗した原因を掘り下げることで、次回は成功に近づくことができます。

場合によっては「わざと」メチャクチャなアイディアを出すこともあります。これはツッコミどころ満載のアイディアを思いつきで出したかのように振る舞いつつ、他のメンバーが釣られて「いやそれは間違ってる」「それじゃダメじゃないですか」と発言してくれることを期待してのことです。もちろんそこで、釣り宣言をしてやーい釣られたバーカバーカとか言い出さないように。相手の指摘が適切であることをすぐに認め、自らのアイディアがいまいちだったことを認め、指摘に感謝し(相手の士気が高まり次回以降の発言が活発になります)、可能であればどうしてその指摘が適切だったかを掘り下げるのが得策です。

「確かに、Aさんの仰るとおり、このアイディアだとXXXがダメで上手くいかないね。まてよ、であれば、XXXが満たされればいいわけで、それならXXXXXXならどうかな?」

などと掘り下げのたたき台にできれば完璧でしょう。


現状を振り返る

とはいえ私は一休さんではないので、毎回毎回デタラメなアイディアが思いつくとは限りません。その場合に有用なのはこれです。現状を振り返ってみます。可能な限り細かく砕いて振り返るのが大事です。

「えーと待てよ、今困ってるのは、XXXが、XXXXになっちゃってるからXXXXXができないんだけど、それを解決するためには隣のCチームがXXXXを直してくれないとどうしようもないんだよな。でもCチームはスケジュール的に来月まで動けないとか言ってる。どうしよう。」

これは何も問題を解決していませんが、全員に現状のヒントを与えることができますので、そこから誰かの発言が出てくることを期待することもできますし、現状を振り返ることで自らがネタを思いつくことも期待できます。

「ああ、それならCチームのタスクのXXを我々が引き取って変わりにXXXXを進めてもらえばいいんじゃないかな?そういうバーターはやったことないけど、試して見る価値あるかも」


質問を投げかける

これは問題の解決策を誰かが持っていることが期待できるが発言が出てこない場合に使う作戦です。質問を投げます。

「Yさん、XXXXについては以前あたりのコード調べてた気がするけど、そこなにか知らない?」

質問に対して直接回答が得られれば良いですし、得られなくても追加の質問が行える場合もあります。

「わからないかー、そこ調べてもらったときに誰がそういう仕様にしたか見てもらった気がするけど、誰に聞いたらその辺の経緯分かる?」


正しいか正しくないかではなく好きか嫌いかを問う

これはある事項を決定しなければならないのだが、複数の選択肢の間でみんなが迷っているときに非常に有効な手だと思っています。つまり、こういうことです。

「Aさんはプラン1とプラン2どっちが好きかな?別に良いとか悪いとかじゃなくて、自分が好きだなーって思う方を気軽に教えてほしいんだけど」

「これだけいろいろ考えたけど、どっちもメリデメあって一長一短あるし、どちらに決めても後悔はないと思うので、それだったらよりみんなが好きでやりたいと思うプランを実施したほうがいいからね」

この作戦を取るときに最も大事なのは先ず隗より始めよ、まず自らが絶対に最初に言い出す、という点です。チームメンバーに意見を押し付けてはなりません。

「俺はプラン2のほうが好きかなーなんとなくだけど。1も嫌いじゃないんだけどどっちやったほうが楽しそうかなって言ったら2かな!」

この作戦を取るときには理由なんていりません。理由が付けられないから好きか嫌いかで選ぶんですから、理由をつけず、頭悪く好きか嫌いかでモノを語ってください。これで決まることもあるし、逆にちょっと待ったコールが上がることもあります。そうしたらシメたもので、ちょっと待ったと声を上げてくれた人はなにか違和感があるから好き嫌いで選びたくないと思っているのですから、そこを掘り下げれば解決策がでてくるかも知れません。


最後は自分がやる

あらゆる手段を用いて流れが止まらないように尽力したにもかかわらず上手く議論が進まなかったり、解決策が導かれなかった場合の奥の手はこれしかありません。自分でやりましょう。自分がその箇所を触ったことがあるとか無いとか、使ったことがある言語ではないとか、そういうのは関係ありません。誰もやらない、できないなら、自分が突撃するより他に手がないのです。ひょっとしたらチームメンバーの中には解決策を持っているが、発言したら自らがタスクを引き取らなくてはならなくなるからあえて答えを出さないという人もいるかも知れません。それに対して非難するのは誰でもできますし理屈では正しい事かもしれませんが、それによってメンバーの士気がダダ下がりになってしまうのであればマネージメントのゴールの達成という意味では大失敗です。上手く成功すれば自分のリスペクトも増えますから、決して悪い手ではありません。

こういう最後の手段が使えるように、普段の自らのタスクはやや少なめに拾っておくことをオススメします。やはりマネージメントが最も活躍しなければならない場面というのは問題が発生したときですから。


相手の発言を細かく砕いて言い直す

次に自らが聞きに回っているとき、すなわち守勢にいるときに明日から使えるテクをいくつか並べてみます。

会議のときなど、時々誰かが余りにも省略しすぎた発言をすることがないでしょうか?これは非常にありがちなのですが、全ての人間がしゃべるのが得意というわけではありませんので、自分には分かっているけど人には分かっていない前提条件だとか、コンテキストだとか、そういうのをついつい省略して喋ってしまうことがあるのです。そのようなときに、あえて細かく質問を投げかける形で聞き直すようなテクがあります。

例えばこういう感じです・・・「えっとごめん、今XXXXって言ってたのは、要するにXXXがXXXXでXXXXXだからXXXXだって話ってことであってる?念の為に確認したいんだけど」

これは特に発言者の発言が不用意で分かりづらかったときほど効果を発揮します。自らが分からなかったので教えて欲しい、という立場を取ることで、発言者を責めたり悪い気持ちにさせることもなく、周りのチームメンバーとの認識のズレを正すという効果を発揮しつつ、リスペクトも得られるからです。さらにここから流れを自分側に引き寄せて自らが追加で意見を述べることもできます。余りにも一人の人物が喋りすぎて場が独壇場になりそうな場合の有効な切り返し策となりえます。

もちろんあまりにも頻繁に聞き直したら嫌われますし、あまりにも見当違いな聞き直しをしたらただの馬鹿だと思われますのでくれぐれもご注意を。


「他人を褒める時は大きな声で、けなす時はより大きな声で」

言わずと知れた某銀河帝国の提督様の家訓でありますが、少なくとも私にとってはこれほどしっくり来る人生哲学はありません。特に前半が極めて重要だと考えております。すなわち、人を褒めるときは大きな声で、すぐにその場で、どうして褒められるべきか理由を添えて、己の本心から褒める、これが最も大事です。正しい賞賛は味方の士気を大いに高め、モチベーションを作り、本人の成長と自立を促すことにつながります。

これも守勢のときに使える有効な作戦の一つです。

逆に後半部分ですが、これは敵に対して用いるべき方法で、チームメンバーの問題点を指摘する際には後から、人とは別の場所で、改善のための具体的な方法を添えて、私心を加えず指摘する、つまり褒めるときとはまるで逆のことをやるのが大事であると思います。


他人の表情を見る

自らが発言の主導権を持つときも、他人が主導権を持っていて聞き役に回るときも、どちらでも大事なことは、相手の表情を見ることです。今このご時世ですから会議はZoomでリモートでというのが当たり前だと思いますが、絶対に顔を出すようにしてください。少なくとも私は常に顔出し状態にしています。このほうが自らはきちんと会議に参加しているのだというリスペクトを得やすいです。裏で内職をしていないという証明みたいなものですね。それに自らが発言の主導権を持って進めているときに誰か他に発言したそうな状態の人を発見することもできますし、他の人が主導権を持って進めているときに相手に対して表情だけでも返事することができれば相手は進めやすく感じてくれるはずです。

これは会議に置けるマナーだとか言うつもりはないのですが、単純にそのような行動をするだけで他人から容易に一目置いてもらえるのに、カメラをOFFにしておく理由はないです。私に言わせればそれだけで大量のリスペクトを無駄にしています。

さらに他人が裏で内職をしている徴候をいち早く察することで、今の会議の状態を改める必要があることに素早く気づくことができます。内職をしている参加者は自らが参加している必要がないと思っているから裏で内職しているか、または他により大事なタスクがあったり締切に間に合わないから内職しているわけで、いずれの場合でも何かが上手く行っていない徴候です。会議の量を減らすとか、参加しなくていいものに呼ばないとか、タスクの割り振りが間違ってるとか、そういうマネージメントに必要な情報を得るのに相手の表情を見るのはとても適しています。


最後に一番大事なこと

チームリーダーだろうがマネージャーだろうが社長だろうがなんだろうが構いませんが、マネージメントのお仕事をしている人にとって最も大事なことは、先程までに述べた内容と矛盾しますが、実は自分の身を守ることではないかと考えています。要するに、もらっていない給料の分の仕事まで責任をとってはなりません。マネージャーは魔法使いでも神様でもチート能力を持った異世界転生主人公でもありませんので、無理な仕事は無理です。責任感があるのは素晴らしいことですが、できないことをできると言い張るのもそのためにチームを付き合わせるのも全てそれ以上に無責任なことです。とっとと逃げましょう。退職しましょう。あなた一人がチームから消えたところで人類全体の幸福にはほぼ何の影響もありません。むしろチームメンバーをそのような終わっているプロジェクトから守ってあげるために、さっさと退職させてあげたり、別の仕事を紹介してあげるほうが、人類のためになるのです。



長くなりましたが以上になります。何かしらの参考になれば幸いです。


明日はtokibitoが担当です。お楽しみに。


2019年12月7日土曜日

最近のクルマの話

こんにちわ、毎年恒例 pyspa Advent Calendar も今年は2019年となりました。12月7日担当のakisuteです。明日の担当は @rokujyouhitoma です。

さて皆さん突然ですが、クルマは持ってますでしょうか?

持ってない?当たり前ですね。馬鹿みたいに高い税金と車両代金と高速道路通行料を搾取されるだけで何一つメリットありませんから。

それでは皆さん、スマホはお持ちでしょうか?

持ってる?馬鹿にすんな?当たり前ですね。今どきスマホ無いと生活が困難ですね。10年ほど前はどうやって電車の車内で時間を潰していたのかすら、もはや思い出せそうもありません。

そういうわけで、私のブログをわざわざ見に来てくださっている方はIT業界、それもスマホアプリ関連の業界の方が大多数でしょうから、スマホについてはバリバリ詳しいけど、クルマなんて持ってないから何一つ知らないし興味もないよ、という方が多数派を占めてらっしゃるのではないでしょうか。本日はそういう多数派の方向けのお話をさせていただきたいと思います。

さて、皆さんがクルマに何の興味も知識もない前提でお話を進めさせていただこうと思うのですが、それでも平成以降に製造されたクルマにはカーナビとかいう地図とか表示するディスプレイが付いていたり、スマホをBluetoothで接続したりしてカーオーディオを聞いたりできるということぐらいはご存じの方が多い、と私は勝手に信じております。ところが今や元号も令和となりまして、どこもかしこもインフォメーションテクニック的なヤツが幅を利かせる世の中になっておりますゆえ、当然クルマに搭載されているカーナビですとかカーオーディオ的なやつもご多分に漏れず高機能化しています。おまけに最近は自動運転 (=カーナビの現在位置情報や道路情報を車両側が使用したい) ですとか、クルマの走行特性モードの設定 (=車両側の走行特性をUIから操作する必要がある) ですとか、クルマのハンドルについているスイッチからカーオーディオを直接操作したい (=車両側の入力をカーオーディオと連動させなければならない) ですとか、そういう昭和の時代では考えられないような高度な統合処理が必要な機能の搭載がクルマにとってもはや必須となっておりまして、昔のように後付で買ってきたカーナビやカーオーディオに配線すればOK、というわけにはいかなくなってきました。

そこで、ここ2年ほど以内に発売された新車の真ん中に鎮座するディスプレイはカーナビではなくマルチファンクションディスプレイとかディスプレイオーディオとか呼ばれるようになってきておりまして、タッチパネルを装備し、カーナビ、オーディオ、エアコン、車両の設定などを直接タッチ操作で行う高度なシステムに変貌しています。

それだけには留まらず、今年発売された新車に至っては4G接続用のSIMとアンテナが装備されており自立通信が可能で、電話は当然として緊急時の連絡サービスや、煽り運転されたときにボタンひとつで自動的に通報してくれるサービスもあり、カーナビの地図情報の自動更新やシステムアップデートもこなすことができます。なぜクルマにこのようなものが必要かといいますとこれまた将来的に重要になる自動運転が絡んできまして、最新の地図が常に使用されていないと自動運転は危険だからだとか、万一なにか問題があったときに自動運転中の車両を遠隔監視できていないと駄目だとかそういう理由があります。そこで先んじてこのような通信能力をクルマに持たせているというわけです (※おそらくは裏で匿名運転データの収集も行っているのではないかと推測していますが、そのへんは不明です) 。

さらには昨今のスマホ社会を反映し、各社自動車メーカーが用意したスマホアプリと車両が連動して、スマホアプリから現在の自分のクルマの位置を調べるだの、走行距離とガソリンの残量を調べるだの、カーナビに目的地を送信するだの、果ては走行前に社外からエアコンをONにしたりクルマのドアロックをスマホアプリから開けてしまうだのといったことまで可能になっているのです。

どうでしょう、まるでスマホみたいですね。
そのとおり、最近のクルマにはちゃんとしたOSがいます。

このクルマのOSは現在のところ基本的には各社自動車メーカーが内製で作っている (かまたは基本システムだけ買ってきて各社勝手にカスタマイズして使っている) ものが多いようで、iOSとAndroid以外のOSが事実上絶滅したスマホの世界とは異なり、どの会社からクルマを買うかによって大いに出来栄えと機能に差がある状態です。

中にはスマホ世代の我々にはひと目見ただけで開発者をコンクリ詰めにして東京湾に投げ捨ててやりたくなるようなひどい代物も多数存在します。それどころかタッチしてから0.5秒遅れで反応するUIなどといった、初代iPhoneどころかAndroid 1.5 Cupcake世代の産業廃棄物スマホにすら劣るレベルの実装すら、世の中のクルマに存在します。

ヤバいですね。何処のドイツでしょうか、そんなひどいブツを作るのは。実際に見てみたいと思いませんか?

・・・ここで、ちょっと話は変わるのですが。

メルセデスというクルマのブランドがあります。

あまりクルマに詳しくない人でも、ベンツといえば分かるでしょうか。そう、ドイツの高級車メーカーです。最近はメルセデスという名前で名乗っていますので、メルセデスと呼ぶことにします。

でそのメルセデスといえば、皆さん誰でもすぐに高級な外車で、金持ちが乗ってそうなイメージを浮かべると思います。当然、見た目も高級だし、内装も高級だし・・・

・・・車載OSの動作だって高級で高品質を期待します。当たり前ですよね。下手すると1000万円とか払うクルマなわけですから、iPhone 11 Proみたいにきれいな見た目で高速にちゃんと動作することを期待したいじゃないですか。iPhoneなんて10万円かそこらしかしないんですから。

じゃあ見てみましょうか。メルセデス。でもなぜだか知らないんですが日本仕様・右ハンドル・日本語表示のMBUX (Mercedes Benz User Experience) のUI、ネット上にほとんど落ちてないんですよね。しょうがないから実車の写真を撮ってきました。

ネットから拾ってこれた左ハンドルでの画像ですが、横一列につながった超ワイドなディスプレイ、一見なかなかカッコいいですね。高級感もあるし、これは期待できるのでは・・・

って思った?残念!半角カナちゃんです!

見ての通り、細部に至るまで半角カナです!

 こっちは半角カナじゃありませんがガソリンスタン...になっちゃってます。

幸いにしてタッチパネルの操作感度はまぁまぁ良好だし、タッチしてから1秒以上固まるみたいな絶望的な遅さは無いのですが、どう見ても初代iPhone 3Gとドッコイドッコイ程度の動作速度しかありません。そもそも走行中にカーナビを操作したくなったら、身を乗り出してこのタッチパネルを手で触れというのでしょうか?まことに素晴らしいUXだと思います。

引用元: https://www.elasticfeed.com/44db3e868b3b3bfe82835c65441ea3ca/

もちろんそのような危険なことをしないで済むように、こうして中央手元にMagic Trackpadもどきが付いているのですが、手触りはともかくこいつの反応が10年前のWindowsノートパソコンのほうがマシなのではという次元でして、自分のmacに触れた後にこいつに触ると引きちぎって車外に投げ飛ばしてやりたい気分に駆られること間違いありません。設定で感度を調整したりもできますがどう調整してもイライラするので、結局中央のタッチパネルを身を乗り出して触るほうがマシだったりします。

その他、ハンズフリー操作のために音声アシスタント、いわゆるSiriもどきがついてるのですが、社内での会話中にうっかり「メルセデス」という単語を口にした瞬間「なにか御用でしょうか」と起き上がってきて大変邪魔です。名前を呼んではいけないあの人扱いみたいになっています。しかも初代のSiriより頭が悪く、基本的に何お願いしてもマトモに対応してくれないので使えません。お願いだからOK Googleと席を変わってほしくなります。



極めつけはカーナビです。なんとこちら1年近く道路情報が更新されていないようで、設定画面から最新状態に更新しているにもかかわらず半年前に開通した道路が地図上に存在しません。当然カーナビはそこを迂回しようとします。全く使えません。メルセデスの人に聞いてみたところ、現在地図データを頑張って作ってるらしいです。頑張ってくださいね。

ちなみにこちら、お見せしましたのはAクラスといいます一番安物のメルセデスですが、実は2000万円以上するメルセデス・マイバッハと言われる最上位車種でも全く同様のMBUXが使用されています。それどころかAクラスは今年モデルチェンジされたため、下手するとそれらよりも最新のOSが搭載されています。要するに2000万円以上する超高級車でも1年前の道路しか存在しないカーナビを使わされるというわけです。まぁ、そんなクルマを買うような人は自分で運転なんかしないでしょうから、何の問題もないのかもしれませんね。

じゃあ、次はメルセデスのスマホアプリを見てみましょうか。

まぁ悪くはないですね。

なんかWebViewっぽい匂いがしますが・・・

一応ネイティブアプリのようです。FOSS (Free/OpenSource Softwares)をちゃんと列挙しているのは好感が持てますね。

一応機能は充実してますね。

見ての通りクルマのドアロックをこのアプリから開けることもできます。

カーナビ連動もありまして、この画面から目的地を検索してクルマのカーナビに飛ばすことも可能なのですが、

見ての通りこの程度の検索すらロクにできませんので使い物になりません。まぁよしんば目的地がクルマに送信されたところで1年前の日本地図に基づいてナビゲーションされてしまうので、どっちにしろ使い物にならないと思いますが。

いかがでしたでしょうか。まぁ、車載MBUXに比べると幾ばくかマシかもしれませんが、2000万円以上払った人専用アプリなんてものはございませんので、最廉価のAクラスユーザーでも最上位のVIPユーザーでもこのアプリを使わされることになります。もうちょっと頑張れよと思わないでも無い気がします。

一応、弁護させていただきますと英語版やドイツ語版は半角カナではないのでフォントはマシですし、多分ドイツにサーバがあるのでドイツで使ったほうがアプリの動きも多少はサクサクだと思いますし、ドイツ国内のカーナビは多分1年遅れで更新されるとか言うことも無いはずです。要するに日本版が飛び抜けてショボいだけかもしれません。あとクルマ自体は普通にとんでもなく良かったので、アプリとか気にしない人にとっては最高のクルマだと思います。

で。
また閑話休題で申し訳ないのですが。

テスラというクルマのブランドがあります。

最近話題になることが多い電気自動車のメーカーです。あのイーロン・マスクの会社というと我々IT業界人には通じやすいのではないでしょうか。何かやってくれそうな気がしませんか?

そのテスラなんですが、こんな感じなんです。

iPad Proより巨大なタブレットのようなサムシングが鎮座しています。

引用元: https://response.jp/article/2019/08/19/325526.html

見てください、これ。まるでiPadのアプリにしか見えません。このテスラ モデル3の社内にはハンドル周り以外に一切の物理ボタンが存在せず、ディスプレイもダッシュボードのメーターもありません。速度計の確認も、エアコンの操作も、ハンドルとアクセルとブレーキとギアの選択とウィンカー操作以外、何もかもすべてこのiPadで行うことになります。

普通にメチャクチャ綺麗です。カーナビに至ってはおそらくこれGoogle Mapsそのものです。当然、Google Mapsですから、1年前の日本地図が表示されることもなければ、パチンコガンダム駅が存在することもありません。完璧に最新最先端の地図が無料でいつでも使えます。素晴らしいですね。

では、テスラのアプリはいかがでしょうか?

当然のようにネイティブです。まぁReact NativeかもしれませんしFlutterかもしれませんが。




どうみても出来が良いです。半角カナなんて汚物は当然存在しません。

これで、テスラ モデル3の車両価格は最高でも717万円、最安値ですと511万円で収まります。

以上で大体私の申し上げたいことはなんとなく伝わってきたのではないかと思います。つまり、我々スマホ開発者界隈が買うべきなのはテスラってことです!さぁ、このテスラの新車を今すぐ予約してあなたも未来を体験しましょう!



・・・やっぱりメルセデスのほうがいいですね!メルセデス最高!



最後に余談になりますが、Apple CarPlayとAndroid Autoについてちょっと話します。この2つはスマホ開発者界隈の皆様も少しくらいは聞いたことがある名前ではないでしょうか。これまで見てきましたとおり、最近のクルマには車載OSが存在するのですが、Apple CarPlayやAndroid Autoは車載OSのアプリの一つとして動作します。要するに車載OSのナビアプリを開いたりオーディオアプリを開く感覚で、CarPlayアプリを開いて、その中でCarPlayのUIの中で更にiOSのアプリを操作する、みたいな作りになっています。

引用元: https://www.elasticfeed.com/44db3e868b3b3bfe82835c65441ea3ca/

そのせいで、見てのとおりに画面が狭いです。どうやらApple Carplayは7インチの画面を前提に作ってあるようで、10インチのワイド画面であるメルセデスのディスプレイオーディオにはフィットしません。しかしながらこの中は完全にiOSであり、マトモなGoogle Mapsが機能します。おまけにスマホと車体が連携しており、車体側から車載GPSやジャイロコンパスなどのより正確な情報を提供してもらえるため、スマホ上で使うGoogle Mapsより段違いに自車の現在位置精度が高くなります。

参考: https://developer.apple.com/documentation/carplay
参考: https://developer.apple.com/design/human-interface-guidelines/carplay/interaction/car-data/

なんかクルマ向けにアプリ作ってみてえなと言う人がいらっしゃいましたら今がチャンスかも知れませんのでぜひぜひやってみていただければと思います。まぁ、デバッグに実車が必要・・・かもしれませんけど・・・

最近は国産車でもトヨタ・カローラという昭和のジジイ以外だれも知らないようなオワコンカーがびっっっっっっっっっっくりするぐらいモダンで素晴らしいクルマに生まれ変わりまして、そちらの新型トヨタ・カローラには標準でカーナビがついておらず、Apple CarPlay / Andriod Autoやトヨタ独自のSDLという規格を利用してスマホをナビにすることを前提の作りになっています。まさに今のスマホ時代にふさわしい素晴らしい方針だと思います。

2019年9月24日火曜日

SwiftUI で ScrollView / Listの現在のスクロール位置 (UIKitにおけるcontentOffset) に相当する値を参照する/コード上から指定する方法は iOS SDK 13.0 地点では存在しない

タイトルの通りですが一応補足しておきます。

先日、奇しくもAppleのSwift UIを実際に手掛けている開発者に直接質問する機会に恵まれましたので以前から気になっていた内容を質問してみたのですが、やはり現段階のリリースではcontentOffsetに相当するものの変更タイミングを取得したり、またプログラム的にcontentOffsetを調整することもできないと明言されてしまいました。

ただしcontentOffsetの変化したタイミングを取得するだけであれば、以下の方法で擬似的に再現することができるとアドバイスを頂きました。


  1. ScrollView / List 上の特定の位置に、ダミーの隠しViewを配置する。
  2. 隠しViewのonAppear() / onDisappear() を利用する。


彼曰く、コミュニティの誰かが作ったサンプルのVideoPlayerアプリがこのテクを使って動画が画面内に入ってきたときに自動再生を開始する挙動を実現していると言っていたのですが、具体的にどのサンプルアプリなのかは教えてもらえなかったので発見できず。残念。

あとは例によっていつものごとく、機能追加が欲しい場合は https://developer.apple.com/bug-reporting/ 経由で要望を上げてくれると対応できるよと言っていましたので皆さんガンガン書けばいいと思います。

2019年6月8日土曜日

SwiftUI 未解決問題まとめ

一通り試してほぼほぼ理解できたのですが、現状どこをどのように調べてもわからなかった内容がいくつかあるので未解決問題としておいておきます。誰か教えて\(^o^)/

Transition

type-eraseされたAnyTransitionはSwiftUI.frameworkに居るのですが、元のProtocolが見えない上にドキュメンテーションも一切ありません。おそらくはNavigationViewの中で使われているのだと思いますが詳細不明。

ScrollView / Listの現在のスクロール位置 (UIKitにおけるcontentOffset) に相当する値を参照する/コード上から指定する方法

今の所、一番怪しいのが以下のpreferenceの仕組みではないかと睨んでいるのですが、
問題は肝心要のPreferenceKeyの具体実装がSwiftUI.framework上には一切見つからず、したがってキーが指定できないためonPreferenceChange(_:perform:)がうまく利用できません。特定位置までスクロールしたら発火、とかビューが50%スクロールして隠れたら発火、とか普通に使いたいのですが、困りました。それとかあとはenvironment経由なりイニシャライザ経由なりでinitialScrollPositionのようなプロパティを用意してScrollViewのスクロール初期位置を与える、みたいなテクも使いたいですし、普通に必要だと思うんですけど(´・_・`)

ちなみにView.offsetではない・・・と思います、たぶん。一応念のためにList.offset()で試してみましたが、ドキュメンテーションにもある通り、全く違う挙動になります。

SwiftUI チュートリアル ヘルプ ドキュメント FAQ 困ったらとりあえずここ見ればOK

https://github.com/Juanpe/About-SwiftUI

いろいろ調べたのですが、これよりよくまとまっているドキュメントを現状発見できませんでしたので、2019/06/08現在では上記のドキュメントを参照するのがベストだと思います。

特に以下の記事は役立ち度が高かったです。この2つだけで問題の9割ぐらいは解決できると思います。

SwiftUI by Example
https://www.hackingwithswift.com/quick-start/swiftui

Answers to the most common questions about SwiftUI
https://wwdcbysundell.com/2019/swiftui-common-questions/

あとは直接SwiftUI.frameworkの中身を見るのが良いと思います。正直Appleのドキュメンテーションは未だにSwiftのExtensionベースの実装をきれいにドキュメントに起こす事ができておらず、複数のドキュメントに重複した記載が見られたり、どこで定義されているfunc/varなのかを正しく表現できていなかったりします。なのでシグネチャの名前さえわかっていればSwiftUI.frameworkの中を自分で検索したほうが正確にどういう定義になっているか判断できて便利です。

2018年12月19日水曜日

HTML5 video / audioがiOSデバイスの消音スイッチの状態に従うようにする方法 (UIWebView編 / WKWebView編)

いろいろ調べていたのですが、遥か大昔に私が書いたブログ記事が長い年月を経て今や大間違いになっていたのでここに訂正させていただきたいと思います。

今回ご紹介するのはUIWebViewまたはWKWebViewで表示しているHTML5のvideo要素やaudio要素が音声を出すときに、iOSデバイスについている消音スイッチ (ミュートスイッチ, mute switch, silent switch) の状態を無視してしまう問題を解決する方法です。相変わらず紹介内容がとてもニッチですね。

ちなみにSafariはデフォルトでちゃんと消音スイッチの状態を反映してくれるので、SafariでYouTubeの動画を見ててもいきなり音が流れ出すことはありません。素晴らしい!というわけで我々のアプリもぜひそのようにしたいと思います。

消音スイッチの挙動について

まず基本的なおさらいとして、消音スイッチがどのような挙動を示すかについてこちらにまとめます。
  • 各プロセスごとに、AVAudioSessionが消音スイッチに対してどのように振る舞うかを定義している。
  • 具体的には、AVAudioSession.Categoryの値に応じて挙動が変化する。ドキュメントにも明記されている。
    • AVAudioSession.Category.ambientやAVAudioSession.Category.soloAmbientを指定すると、消音スイッチがONのときは音が出ないようになる。
    • 逆にAVAudioSession.Category.playbackを指定すると消音スイッチを一切無視するようになる。
  • 消音スイッチの現在の物理的な状態を取得するAPIは一切ない。Private APIで以前は可能だったが、穴が塞がれたためその方法も利用できない。そもそもアプリが提出時の審査で蹴られる。当然JS経由でHTMLコンテンツ上から状態を取得するのも不可能。

解決方法・UIWebView編

UIWebViewはWebKit1を利用しており、したがってUIWebViewのエンジンは我々のアプリ内のプロセスで動作します。そこでUIWebViewのインスタンスを生成するより先に、先述の通りAVAudioSessionのcategoryを変更して消音スイッチの状態を反映してやるように示してやるとうまくいきます。
try? AVAudioSession.sharedInstance().setCategory(.soloAmbient, mode: .default, options: [])
try? AVAudioSession.sharedInstance().setActive(true)
ただしご存知の通り、すでにUIWebViewはdeprecated扱いとなっており、WKWebViewへの移行が推奨されています。そこでWKWebViewでも同様の方法が使えないかやってみましょう。

解決方法・WKWebView編

ありません。

繰り返しますが、ありません。WebKit2の設計上のバグです。

今後修正される可能性もほぼ間違いなくありません。諦めてください。

一応、順を追って説明します。
  1. WKWebViewはWebKit2で実装されています。
  2. WebKit2は我々のアプリ内のプロセスで動作するのではなく、「共用の」WebCoreプロセス上で動作し、その結果が我々のアプリ内に転送されてくるような実装になっています。
  3. 「共用の」WebCoreプロセスは(これは推測ですが、audioやvideoを最大限に活かすため)AVAudioSession.Category.playbackとAVAudioSession.Mode.moviePlaybackで動作するように設定されている用に見えます。したがって消音スイッチは無視されます。
  4. 最初にご説明したとおり、AVAudioSessionによる消音スイッチに対する振る舞いは「プロセス単位」で制御されており、これは遥か大昔のiOS 2.0どころか下手するとNeXTSTEPの時代からCarbonレイヤーで決められている挙動だったりします。要するに今からの変更はほぼ不可能です。
  5. もうおわかりだと思いますが、「共用の」WebCoreプロセスの挙動を我々個別のアプリがAVAudioSession経由で勝手に変更することは不可能ですし、これを可能にするのはiOSとWebKitの設計上実質不可能なため、問題は解決されません。
    1. WebCoreプロセスを各個別のアプリごとに立ち上げて対応しろよ!と思うかもしれませんが、WebCoreプロセスは近年AppleのOSに組み込まれている特権階級モードで動作するプロセスとなっており(そのためメモリに無制限なアクセスが可能で、JSをJITコンパイルして高速に動作させる事が可能)、最近のセキュリティとバッテリーライフにうるさいAppleがそれを個別のアプリごとに立ち上げさせるなどということは現経営陣が全滅しない限りありえないと断言できます。
    2. 共用のWebCoreプロセスが使用するAVAudioSession.Categoryを変えてしまえばいいだろ!とも思いますが、実はAVAudioSession.Categoryをplaybackに指定しない限りバックグラウンドで音楽を流し続けることができません。したがって今度はWebViewで音楽プレイヤーを作ったりPicture in Pictureで動画を流し続けるアプリが全滅するため、これも不可能です。
    3. だったら消音スイッチの状態を自分で調べて自分で動画をmuteにすればよいのでは、と思いますが、これも先述の通り消音スイッチの状態を調べる方法は一切ないため、一律でmuteにしてしまうなどの乱暴な方法を用いない限り対応できません。
やばいですね☆

iOS開発でエラーコードを調べるときはOSStatus.comを使おう

久しぶりに書く価値のあるネタが見つかったのでご紹介します。

iOSのフレームワークがNSErrorを返してきたとき、そのcodeが何を意味するのかを調べる必要が出てくることが往々にして発生します。新し目のフレームワークは比較的簡単に調べられるようにまとまっているのですが、厄介なのがOSStatusなどの大昔から存在するエラーコードの場合です。

NSError コードの調べ方 こちらのブログ記事で紹介されている通りに一つ一つヘッダファイル内を探す方法でもいいのですが、もはや平成の終わりが目の前に迫っている2018年の年の瀬にもなってこのような原始的な方法を使っているようではよろしくありません。

そこで OSStatus.com の出番です。こちらの検索欄にcodeをコピペして検索ボタンを押すだけであらゆるエラーの詳細が一発で帰ってきます。実際にやってみましょう。


一発ですね。素晴らしい。


名前での検索もバッチリです。

偶然見つけたのですが、はてブもほとんどついてないし、ネット上で紹介されている記事も全く見つからなかったので書いてみました。便利です!

2018年12月1日土曜日

2018年のしめくくり

pyspa Advent Calendar 2018 12/1です。

早いもので、あっというまに2018年も終わりを迎えそうな時期になってまいりました。皆様ご無沙汰しております、akisuteです。今年もまとめだけ書いて終わりにしたいと思います。

今年やったこと

JavaとかSwiftとかKotlinとかNode.jsとかReact Nativeとかやってました。Node.jsはなかなかいいですね。食わず嫌いで最近まで手を出しておらず、昔はお手軽になにか作りたいときはもっぱらPythonだったのですが、今ではついついNode.jsを使うようになってしまいました。特にTypeScriptが大変気に入っております。

細かいところですとチームのドキュメンテーションの問題を考えている時間が増えてきました。というのも最近ようやく気づきを得たのですが、プログラマの中にはドキュメンテーションができるタイプの人と一切できないタイプの人の二種類がいるように思えます。後者のタイプの人がドキュメンテーションが不得手な理由を自分なりに考えていますが、
  • 「自分が理解しているので、相手も理解しているだろう、相手も理解できているだろう」という考えがあり、そのため本来必要であるドキュメントが不用と判断されて欠落してしまう。
  • 思考が直接コードで行われているために、わざわざ日本語なり英語なりの言語に変換されない。またはその変換コストがその人にとって高い。
  • 間違った情報ということは認識しているのだが、既存のWikiやコードコメントを書き換えるのを遠慮してしまう。
これらが原因なのかどうか、いずれも定かではありません。テンプレートを整備してみたり、OpenAPI+ReDocのような解決策に頼ってみたりしているのですが、なかなか成果が上がっておらず。ドキュメントが不足しがちな人をあえてドキュメントが必要な状況におく(普段とは違うプロジェクトをアサインして、ドキュメントを読まなければにっちもさっちもいかない状態にすることで、どのような情報が欠落すると自分が困るのかを理解できる)とかはいいアイデアなのでは?と思っています。ドキュメンテーションの得意な人と組ませて、得意な人がレビュープロセスなどで書き加えるというアイデアなどもなんとなく回りそうな気はしています。なかなか難しいです。

今年のGotY

Forza Horizon 4以外にありえないですね。これより優れたクルマゲームは地球上に存在しないと断言していいレベルで素晴らしいです。RDR2は正直雰囲気と世界観のためにゲーム性を犠牲にしすぎている気がします。1ほど楽しめませんでした。どうやら私もおっさんになったようです。

今年のマイブーム

Forza Horizon 4のせいか急にクルマがマイブームになってきました。と言っても別に今すぐクルマを持ちたいとは思っていません。なにせ現実世界のクルマはカネがかかり、乗っても楽しく乗れる場所はなく、ただひたすら渋滞とマナーの悪いドライバーに憤慨し、事故とスピード違反に怯えながらほそぼそとアクセルを踏まなければならないような代物です。全く執着するに値しません。
しかしながらゲームの中となると、たかだか1万円で何百車種もの好きなクルマに好きなだけ乗ることができ、キレイな風景や楽しいコースを好き放題乗り回し、渋滞もなく、マナーの悪いドライバーは遠慮なくポルシェ・カイエンターボで粉々に踏み潰すことができ、事故ったところで現実世界の私はかすり傷一つ受けることもないため何のリスクもなくクルマの限界に挑戦できます。まさにクルマの楽しい箇所だけをすべて味わい尽くすことができるのです。うーん、仮想世界って素晴らしいですね。

まとめ

今年も平和でいい年が過ごせて100%満足しています。よかったです。
来年も平和で良い年でありますように。

2017年12月4日月曜日

2017年のしめくくり

pyspa Advent Calendar 2017 12/4です。

どうもお久しぶりです。オンライン上では一切活動しておりませんが、おかげさまで大変元気にやってます。というわけで2017年のまとめを書いておこうと思います。

そもそもなんで最近ブログ書いてないの

書くことがないからです。というのも私は最近iOS/Androidの開発ではなくジャバでサーバサイドアプリケーションを書くみたいな仕事をしていて、別にSpring Bootの話なんかここに書いてもあまり面白くもなければ、すでにありとあらゆる先人が地雷を踏み尽くしていて調べればだいたいなんでもわからないことは分かる状態になっているので、わざわざ私が書く必要もないと思われるためです。

なんでiOS/Androidやってないの

端的に言えば愛想が尽きました。iPhone Xは買っていません。SwiftとKotlinは大好きで今でも仕事で使ったり他人のコードをレビューしたりする毎日ですが、もはやiOSもAndroidもどちらも執着するには値しません。

なんか技術的に新しいネタないの

正直今ネイティブアプリに大きな流れはないので(ARとクライアントサイド機械学習程度しか新規性のあるネタがなく、どちらも適用分野が限られ、ほとんどのアプリケーションでは縁がない)、後数年の間はモバイルネイティブアプリ一択だった流れが半分ぐらいウェブに返ってくると思っていて、ゲームなどではすでにその兆候もありますし、React NativeとかモバイルフロントエンドJavaScriptとかを見ておけばいいんじゃないのかなぁと思っています。個人的にはあんまりどちらも好きじゃないんですが、悪いものではないと思います。
また、Rxはもはや使えて当然と思っていますが、しかしながらRxを限界まで酷使するようなアプリはごく少数の人間しかメンテできなくなり、そのうちメンテがおぼつかなくなり、Rxのシグナルやオブザーバを使うのではなく昔ながらのdelegateやcallbackで手っ取り早くコードを修正するような事態が訪れ、ゆっくりと破綻していくような事態が周囲で散見されています。正直人間のほうが技術側に追いついていないというか。使えるやつは使えるんだけどそれじゃメンテ回らないよというか。

なんか注目のビジネスネタないの

フィンテックはガチだと思います。儲かるので。ただしビットコイン、というかブロックチェーン技術を神聖視するのは正直イケてないと思います。
動画配信系もガチだと思います。これもカネの匂いがします。ただしこっちはそもそもプレイヤーになれる存在が非常に限られており、ドワンゴすらそろそろもうついていけないかなぁという状態ですので、皆様がんばってくださいという感じです。
AIが〜とか機械学習が〜とかはやらなくてはならないのは間違いありませんが、ぶっちゃけ現状ではまだそんな言うほど大したことないです。どっかのタイミングで私みたいな何もわからないド素人でも簡単に放置してデータ食わせるだけで勝手に最良の状態に学習する事ができるような仕組みが誕生すると思っていて、そうなったら本当に爆発的に世界が変わる気がしています。それまでは自動運転みたいなカネが突っ込まれまくる分野でのみ世界が変わるほどの進展が見られるんじゃないかと勝手に思っています。
スマートスピーカーは正直使ってみて要らないと思います。不便とは思いませんが、現状無くてもほとんど全く困らないので要らないです。無いと困るようになったら爆発的に売れるのではないでしょうか。

今年のゲームはどうだったの

ゼルダがGotY 2017なのは間違いありませんが、その他も非常に豊作な一年だったと思います。個人的な推しはtheHunter: Call of the Wildです。

家どうなったの

友人が家を探しているというので色々物件を紹介していたら、まさかの我がマンションに引っ越してきました。おかげさまで大変楽しい毎日です。近所付き合いってのも悪いもんじゃないと思います。
あとはベッドを買い替えました。こちらもiPhone Xを買うより100倍ぐらい幸福になりました。良いお金の使い方をしたと思います。

婚活どうなったの

退会しました。1年間、のべ数百人単位の女性を紹介してもらって、数十人単位と付き合って、数人とじっくり時間を過ごしてみた得た結論は、正直私は女性と付き合っても煩わしいばかりで楽しくないし、相手も私といても満足できないし、結婚してもいいことはないというものでしたので、そのようにしようと思います。1年前はちょっと焦りとかもありましたが、今では大変気分も落ち着いて平穏が得られました。自らの人生について考える良い機会だったと思います。

今どうなの

おかげさまで非常に幸福な人生を送っていると思います \(^o^)/
来年もいい年になりますように!

2017年6月19日月曜日

UIWebView, WKWebView 等において Drag and Drop を禁止する方法


iOS 11よりDrag and Drop APIがUIKitに追加され、UITextView / UITableView / UICollectionViewに簡単にDrag and Dropを実現するためのdelegateが用意されたり、それ以外のUIViewにもDrag and Dropをハンドリングするための仕組みが用意されました。このDrag and Dropは基本的にはアプリをまたいでデータを受け渡しすることを前提として作られていますが、一応は自分のアプリ内でデータを移動したりコピーしたりするためにも使えるようになっているので、積極的に活用していきたいところです。

ところでこのDrag and Drop、基本的にはアプリ側が対応しない限り自動的には対応してくれないのですが、例外があります。それがUIWebView / WKWebView / SFSafariViewController要するにWebViewのたぐいの皆様です。これらについては最初からDragも可能ですしDropも可能なように作られているようです。便利ですね!

ですがここをご覧になっている皆様の中には、大人の事情によりどうしてもそのような便利な機能をユーザーさんにわざと提供したくないと言うケースがある方もいらっしゃるかと思います。そこでUIWebView / WKWebViewのデフォルトのDrag and Dropを無効化したり、頑張って自分のコードでハンドリングしたりすることができるようにする方法をご紹介します。なおSFSafariViewControllerに対しては手も足も出ないのでご了承ください。
if #available(iOS 11.0, *) { 
    webView.scrollView.subviews.first?.interactions = []
}
たったのこれだけです。簡単ですね!

なんのこっちゃなので詳しく説明します。

まずはじめにiOS 11よりUIView.interactionsプロパティが追加になっています。このinteractionsは[UIInteraction]型となっていて、公式のドキュメントによると「ジェスチャベースの挙動をビューに定義する」ことができるらしいです。まさにドラッグ・アンド・ドロップ的なやつですね。
で、Appleによって最初からドラッグ・アンド・ドロップ用のUIInteractionすなわちUIDragInteractionとUIDropInteractionが用意されています。これらのInteractionは内部的にdelegateを持っていて、これらのInteractionがインタラクションを検知したらdelegateにメッセージングを行い、そいつらが実際のドラッグ・アンド・ドロップ処理を行うというような仕組みになっているようです。
調べてみたところUITableViewのような最初からDrag and Drop用のdelegateを追加されているViewについても、このinteractionsに何らかのUIDragInteraction / UIDropInteractionが追加されていて、それが一旦イベントを拾ってから我々が定義したUITableViewDragDelegate / UITableViewDropDelegateに問い合わせを行うという仕組みで動作しているということがわかりました。

ここまで分かれば後は簡単で、UIWebView / WKWebViewも同様にinteractionsで一旦イベントを受け取った後に、内部的に処理を行っていると考えられるのでUIWebViewの中身をどったんばったん探してみたところwebview.scrollView.subviews.firstの中にinteractionsが刺さっているのを発見したと言う次第です。

先程の無効化する例では空配列を渡すことで完全にinteractionsを無効化していますが、ここで自分が作ったカスタムのUIDragInteraction / UIDropInteractionを渡してやればうまい具合に自分でWebViewのDrag and Drop挙動をカスタマイズすることができるかもしれません。また両方を消すのでなくて片方だけを消せばDragによってデータを持ち出すのは禁止するがDropによってデータを持ち込むのは許可するみたいなこともできます。

2017年5月24日水曜日

Xcode 8.3 & Swift 3.1 環境で LLDB を使う Tips

以前も似たような記事書いた気がするんですが、定期的にSwiftのコード上でLLDBを使ってて困ることがあるので定期的に書くことにします。ほとんど https://stackoverflow.com/questions/29441418/lldb-swift-casting-raw-address-into-usable-type からの転載です。

LLDBの言語を指定して実行する

標準ではbreakpointを挟んでbreakした行がSwiftであればSwift、Objective-CであればObjective-CでLLDBの言語が選択されるようなのですが、これでは毎回毎回breakした地点に応じてデバッグの仕方が変わって大変で仕方がないので、Swiftに統一してしまうのが良いと思っています。
expr -l swift -- {Swift Command}
e -l swift -- {Swift Command}
とすると常にSwiftでLLDBに対してコマンドを送る事が可能になります。逆にObjective-C側に寄せたい場合は
expr -l objc++ -O -- {Objective-C Command}
e -l objc++ -O -- {Objective-C Command}
とすれば良いです。-Oオプションがないと結果がいい感じにObjective-Cのオブジェクトとして扱われないので注意。

importを忘れずに

以前も書いた気がしますがLLDBでbreakした環境はそのままだとFoundation.frameworkすらまともに使えない(シンボルを認識しない)状態なので、importを忘れずにしましょう。
e -l swift -- import UIKit
e -l swift -- import MyApp
e -l swift -- import MyAppLib
という具合でしょうか。他必要なものがあればその都度。注意点として自分のアプリ自体に含まれるシンボル、例えばAppDelegateだとかViewControllerのたぐいだとかもimportしないと触れないので忘れないように。

unsafeBitCast(_:to:)を使ってポインタからオブジェクトを取得する

これも以前書いた気がしますが、Swift 3でまたシグネチャが変わったらしいので念のため。
e -l swift -- let $obj = unsafeBitCast(0x00000000, to: MyClass.self)
e -l swift -- print($obj)
とかやるといい具合になります。

エイリアスを作ろう

毎回e -l swift -- とかタイプするの面倒ですし、poがe -O -- のエイリアスなのと同様に、eswiftとかpswiftとかそういうエイリアスを作ってしまえばいいと思います。~/.lldbinitの中に、
command alias eswift e -l swift -- 
とか書いておけば良い気がします。

2017年3月7日火曜日

NSAttributedString に lineSpace を付与したとき、1行であるにも関わらず lineSpace が下端に付与されて困っている人はこれを読んだら直ります



突然ですが皆さん、NSAttributedStringには2017/03/07付のiOS 10.3現在でも致命的にバグっている箇所があります。

症状:

  • NSAttributedStringにNSParagraphStyleAttributeNameを利用してNSParagraphStyle経由でlineSpaceが付与されている。
  • NSAttributedStringに複数の「区間」が存在する。例えばNSAttributedString全体が単一のAttributeによって構成されているときはこの問題は発生しません。2つ以上の異なるAttributeの区間が必要です。
  • NSAttributedStringを描画するときに、横幅及び文字列の長さの都合で、1行で描画される。複数行になるときにはこの問題は発生しません。
  • NSAttributedStringにNSBackgroundColorAttributeNameが付与されていない。または、NSBackgroundColorAttributeNameとNSKerningAttributeNameの両方が付与されている。

上記の条件を全て満たすとき、
本来、1行の文字列はレンダリングしたときに下端にlineSpaceが付与されてはいけませんが、この条件が満たされていると下端にlineSpaceが付与されてしまいます。先頭の画像の左上のケースがこの問題に相当します。

具体的な問題としては、
  • 問題が発生するNSAttributedStringを使用したUILabel, UITextField, UITextViewの描画内容が思いっきり上にずれます(下に無駄なスペースが発生するので)
  • NSAttributedStringの地点で壊れているので、Core Textを利用したり、boundingRect(with size: CGSize, options: NSStringDrawingOptions = [], context: NSStringDrawingContext?) -> CGRectを使っても一切回避できません

解決策: 

この問題に対する正しいワークアラウンドの方法は一つしかありません。

NSAttributedStringの全Attribute区間にNSBackgroundColorAttributeNameを付与し、かつどの区間にもNSKerningAttributeNameを付与しない。

背景色が不要の場合はUIColor.clearでも付与してごまかしてください。
以上です。よろしくお願いします。

参考:

2016年12月13日火曜日

Instruments を使っていてシンボルが見えないときの対処法

Instruments を久しぶりに起動して Time Profiler を使おうとしたら、びっくり仰天シンボルが全部見えない状態になっているじゃあありませんか。 Swift化したのがあかんのか!?と思って調べてみました。

結論から言うと、先日ビルドの軽量化のためにDebugビルド時にdSYMの出力を止めていたのが原因でした(´・_・`)
http://stackoverflow.com/questions/36882788/how-to-create-dsym-file-in-xcode-7-0
Debug Information FormatをDWARF with dSYM Fileに戻して、dSYMの出力を再開したら問題なくシンボルが出力されるようになりました。なんじゃそりゃ。

それでもだめな場合はInstruments側のFile -> Symbols... を選択すると、直接モジュールのdSYMを指定する事が可能になります。覚えておくと便利かもです。
http://stackoverflow.com/questions/33683690/apple-instruments-has-mangled-symbols-and-greyed-out-symbol-names-when-profiling

2016年12月1日木曜日

pyspa Advent Calendar 2016 1日目: 今年の話

去年に引き続きまして pyspa Advent Calendar 2016 一番槍担当の斧さんakisuteです。よろしくお願いします。

去年はゲームの話をしましたが、今年は人生に一度しかやらなさそうなイベントを大量に発生させましたので、主に今年何をやっていたのかについてご報告させていただきたいと思います。

1. 家を買いました

ずっとワンルームのアパートにしか住んだことがない男だったのですが、30過ぎたので人生一度きりだし家でも買ってみるかと思い、半年ほど探して思い切ってタワーマンションの部屋を買ってしまいました。

正直ちょっと前まで家を買うとか単に負債を抱えるだけの大アホだと思っていたのですが、実際に買ってみると案外悪くなかったです。売ればいいとか資産価値があるとか賃貸より買ったほうが割安とかそういうことはさんざん世間様がおっしゃってるかと思いますので、ここではあんまり世の中では言われていない気づきを書いてみようかと思います。

買うと(当たり前だけど)自分のものになる

賃貸で引っ越しするのとはまるで違う感覚です。まず引き渡しですが鍵と権利書をもらうだけです。クリーニングすらされてません。売主は貸主様じゃないので当たり前です。そこでハウスクリーニングを自分で呼んで掃除してもらい、あとは業者を呼んで鍵を付け替えてもらったりします。なんというか、自分のものなんだな、今まで家を借りてた相手の家主さんというのはこういうことをやってたのかな、という感じがします。

当然(マンションの管理規約の範囲内で)部屋は自分のものなので、壁に穴を開けようがぶち破ろうが工事してみようが全て自由・自己責任となります。逆に老朽化した設備を保守点検するのも自分の責任となります。とにかくなんというか、守るものができたなぁという感じを大いに受けます。

売買は意外と大雑把

私の場合売主さんが全ての鍵を渡すのを忘れてましたというのが後から発覚して大騒動になりました。最終的には無事全部私の手元に来たのですが、大手の不動産仲介屋というのも案外雑なもんだなという気持ちになりました。

あと管理費・修繕積立金の将来の計画(当然年度が上がるごとに高くなる、大雑把に言って5年おきに値上がりで、30年で2倍に上昇すると見積もればだいたいOK)ですとか、固定資産税の額ですとか(これは実際に買うまで見積もりもなかなかできない、年間20万円ぐらいすることもある)、家が広くなるので水道光熱費が上がるとか、そういう諸費用は契約直前までなかなか教えてくれないので注意した方がいいです。大体不動産屋も銀行もローンと最初の管理費・修繕積立金ぐらいまでしか計算に入れずに大丈夫ですよとか言って勧めてくるので目に唾を付けて聞いてください。私の場合はお願いした不動産屋さんが知り合いのツテで、大変親切に説明していただいたお陰で難を逃れました。

買うと銀行が身近になる

家を買わない限り銀行なんてただの財布の延長程度の扱いでしかない、という感覚だと思うのですが(特に私と同年代以下の方は)、家を買うとなると銀行が本格的にお客さんというかパートナーというか商売相手になるというか・・・とにかく全く別の相手になります。銀行の担当の人とは仲良くしましょう。
それから自分の口座から頭金として3桁万円の現金札束を引き出したり、4桁万円の融資が飛び込んできたりするのが目の前で見られてちょっと社長にでもになった気持ちが味わえます。でもできればあんまり味わいたくないです(´・_・`)

買うと強制的に勉強せざるを得ない状態になる

やれ保険があるだのいざとなれば売ればいいだの言われますが、借金は借金です。返せなければ死ぬしかありません。今は金利も安いですが将来はわかりませんし、何より管理費・修繕積立金・自宅設備の更新など、将来必要になるお金は増える一方で減ることは絶対にないと悲観的に考えたほうがよいぐらいです。そして我々の給料はほっといても絶対に上がりません。退職金も年金もありません。

よく家を買うと保守的になるだの守りに入るだのというネガティブな考えを持ちそうになりますが、そんなことはありません。むしろこの激動の時代において、守りに入ったら即座に借金が返せなくなって死にます。死にたくなければ勉強し続け変化し続け攻め続けるしかありません。最大の防御は攻撃です。

そういった理由で最近はゲームをする時間もめっきり減って、代わりに株式投資だの投資信託だのの勉強をしてみたりとか、経済のニュースを見て将来の住宅ローンの金利がどうなるか調べてみたりだとか、仕事もiOSアプリばっかりいじってないでDockerだのansibleだのに手を染めてみたりだとか、筋トレする時間を毎日取って体調を維持してみたりだとか、そういうおっさんっぽい規則正しい生活を強制的に余儀なくされております。

家を買うまではそれまでの努力の成果に甘えてダラダラ過ごせてしまっていたので、家を買って強制的に借金を持って自分を追い込んだのは大正解だったと思っています。

買うと視野が広くなる

生活が強制的に変わるので当然といえば当然なのですが、その他家が広くなるので今まで置けなかった家具が置けるようになったり、筋トレ器具を置けるようになったり、最新のIoTっぽいアイテムを買って試してみたり、カーシェアリングサービスを使ってみたりと、試せるものの範囲が広がります。これは今まで生まれてきてプログラマーしかやったことがない私には大変刺激的です。特にルンバや食洗機には本当に感動していて、私が作ってきたiPhoneのアプリなんてこのルンバの1/100も人の役に立たないと反省することしきりです。

近所付き合いの話

よくタワーマンションを買うと上下格差が〜とか近所付き合いが〜とか言われますが、今私が住んでいるところでは特に上下格差が〜みたいなものは一切見られません。その代わりと言っては何ですが管理組合の人が良くも悪くも恐ろしく有能で厳しい人で、とにかく「マンションの資産価値を守る」という点において凄まじいです。引っ越しの日に私が使った業者の養生がショボかったのを見つけて廊下が割れたらどうするつもりだとものすごい勢いで業者の人に怒鳴ってました。後で菓子折り持って謝りに行きました(´・_・`)

逆に防災訓練を定期的に開催したり、子供向けのハロウィンパーティを開催したり、設備に不備があったらゼネコン建設会社や販売会社のアフターサービス担当に殴り込みに行って無償修理させるなどの活躍をしているようで、敵に回したら怖いけど味方にしたら頼りになるなぁと思って見てます。

近所付き合いに関してはやはり多少はあって、ちゃんと出会った人には挨拶して、お子さんには愛嬌よくして、お隣さんには菓子折り持ってよろしくお願いしますと挨拶に行って、ぐらいは当然必要になります。ですが慣れればなかなか楽しいものです\(^o^)/

2. 婚活をしました

30過ぎたのでいっちょ結婚ぐらいした方がいいだろと思い、ツヴァイというところに申し込んで婚活というやつをしてみましたのでご報告いたします。興味のある方は参考にしていただければと思います。

金の話

大体1年間で30万円払えばOKです。そうすると年間72人だか48人は紹介してもらえることがシステム上保証されます。私はと言うと大体300人弱ぐらい紹介を受けることができました。
なお2年目以降はまた30万円が必要になりますので、短期決戦をおすすめします。なお後述しますがどっちにしろ2年以降続けることはあまりないと思います。

ツヴァイの話

個人的にイオンが好きなのでツヴァイにしたのですが、どうやら婚活業界的には以下のようなヒエラルキーが構成されているようです。

無料アプリ
↓
Omiai, Match, ゼクシィなどの有料アプリ(1万円〜)
↓
楽天オーネット(15万円〜)
↓
ツヴァイ(30万円〜)
↓
パートナーエージェント(40万円〜)

大変身も蓋もない暴言を申しますと、上のものほど婚活とは名ばかりの出会い系アプリで、下の方になるほど今度はアラフォーの行き遅れが滞留する阿鼻叫喚地獄となっております。このことは各社の資料を取り寄せてみて平均会員年齢などを調査すれば分かるかと思います。ツヴァイはだいたい35~40歳、パートナーエージェントになると40〜50歳がボリュームゾーンとなっていました。より上位のサービスで駄目だった人が下に流れてくるという構造があるのかもしれません。

大変な暴言を申し上げてしまいましたが、やはり高い額を払うだけあって、下のサービスになればなるほど入会審査も厳格で(市町村が発行する独身証明書や2年分の源泉徴収票、大学卒業証書を提出する必要があります)、きちんとした担当の方がついてくださってアドバイスを受けたり、相手の女性の方も本気度が高いです。実際に1年間やってみてツヴァイは本当に大満足でしたのでおすすめしておきます。

婚活の話

皆さんおそらく「本当に出会えるのか?」とか「居たとしてもアラフォーの嫁ぎ遅れとサクラばかりなのでは?」とか「自分の趣味に合う人なんているわけがない」とか色々不安があるかと思いますが、断言します。そんなことは一切ありません。普通に魅力的な方ばっかりです。

私のような海外のPCゲームばっかりやってて普通の女の子の話題なんぞ何一つわからないおっさんですら、1年間で300人近く紹介してもらえまして、1/5以上の方には普通にお付き合いの連絡を申し込み、連絡先を交換して実際にお会いしたのが1/10程度で、最終的に趣味がバッチリ合う理想的な女性の方と付き合う事ができました。私自身ビックリです。年間30万円出せて本気で結婚したい方は即座に試す価値があると断言します。

あとはもう一つ気になる、どういう男が人気があるか、ですが、周りの様子を見てみたところ、汚くなくて臭くなくて笑顔が気持ち悪くなければ見た目に関してはどんな人でも全く何の心配もありません。ただし汚いのと臭いのと笑顔が気持ち悪いのだけは即座にアウトで門前払いだったのでそこだけは徹底してください。あとやっぱり身長が高くて体格が良くて声が低い人のほうが(誤差の範疇程度ですが)人気があった気がします。

職業はやはり医者と公務員から順番に売り切れます。付き合ってた彼女もおっしゃってましたが、女性は驚くほど現実を見ます。ただ当たり前ですが医者と公務員じゃないと駄目ということは一切ないのでご安心ください。

むしろそんなことより大事なのは相手を思いやる気持ちをいついかなる瞬間も忘れないことだなぁと思う次第です。

結果の話

そして皆さん気になる結果の方はですが、四ヶ月ほど付き合った彼女に私の不徳のなすところから見事にフラれまして、私が伴侶を持つに値しない人徳のない男であるということが完全に証明された形となりました(´・_・`)
これに懲りて来年以降は変な欲を持たずに良いカルマを積んでいきたいと思います(´・_・`)

3. 焼肉をおごりました





シャトーブリアン、大変美味しゅうございました。

以上、よろしくお願いします。
明日の担当は「お前、誰よ」で一世を風靡したイアン・ルイスさんです。

2016年11月17日木曜日

UITouchGestureRecognizer をやめて UILongPressGestureRecognizer や UIButton を使ってみる

適当なUIViewにUITouchGestureRecognizerを貼ってタッチアクション可能にするという実装を行うことがありますが、UITouchGestureRecognizerはUIButtonと違ってタッチして離すタイミングではなくタッチした瞬間に反応してしまうためユーザビリティ的に望ましくない場合が結構あります。

そんなときはUILongPressGestureRecognizerを代わりに使ってみましょうと言う話です。
http://stackoverflow.com/questions/12830547/how-to-implement-touch-up-inside-in-touchesbegan-touchesended

UILongPressGestureRecognizerというと、長押しして何かコンテキストメニューを表示する際に使うイメージが強いものですが、minimumPressDurationを0.01など十分に短く取ると、事実上タップとほとんど変わらないユーザビリティを得ることができます。さらにUITouchGestureRecognizerとは異なりタッチを認識した後に離すまでの間のイベントをUILongPressGestureRecognizer.stateプロパティ経由で監視することができます。その為例えば
  • タッチされている間は見た目を変える
  • タッチを話したときにアクションを実行する
といった味付けが簡単にできます。

しかしもっと簡単に透明なUIButtonを作って目的のUIViewの上に重ね、そちらにタッチをハンドリングさせたほうがより綺麗で簡単にボタンらしい挙動を再現できたので別にUILongPressGestureRecognizerを使う必要はなかったかもしれません(´・_・`) まぁこういう使い方もあるんだよという参考になれば幸いです。

ビルドが遅いのをどうにかこうにかやりくりする方法

すでに皆様痛感されていると思いますが、Swiftはビルドがとんでもなく遅いです。正確に言うと、Swiftのビルドが遅いのに加え、clang moduleのビルドが遅いため、frameworkの数が増えてくるとビルドにかかる時間がどんどん破滅的なことになってきます。

Swift & dynamic framework導入前はアーカイブ込みで10分以下だったビルド時間が、現在は20分を超えてしまっており、更に今後もSwiftコードの増加ととframeworkの増加に従ってビルド時間が伸びることが予想されます。そこでなんとかしてこの時間を短縮しようと思って調べてみました。

そもそもビルド時間が伸びる原因


  • Swiftのビルドが遅い、特に型推論が遅い
  • frameworkのビルドが遅い
  • Xcode上でcleanを実行するとプロジェクト内でビルドしているのframeworkが全てビルドし直しになり分割ビルドの恩恵が得られない

それぞれ詳しく見ていきます。

Swiftのビルドが遅い、特に型推論が遅い

以下の記事が大変参考になります。
https://thatthinginswift.com/debug-long-compile-times-swift/
Swift 3.0になって随分と高速化したため、型推論のせいで異常に時間がかかるという自体は減りましたが、それでもObjective-Cのコードと比べると10倍以上時間がかかることが多々あります。型を明示すれば高速化に寄与できますが、そうするとSwiftのせっかくの旨味が減るため悩ましいところです。

frameworkのビルドが遅い

dynamic framework = clang moduleのビルドはコードのコンパイル以上の作業を多分に含むため、分割すれば分割するほどそのオーバーヘッドが増えて無駄に時間がかかることになります。

Xcode上でcleanを実行するとプロジェクト内でビルドしているのframeworkが全てビルドし直しになり分割ビルドの恩恵が得られない

個人的に最悪なのがこれだと思います・・・せめて特定のコードに対してのみcleanできれば良いのですが、Xcodeで各種トラブルを避けるためにはcleanは必須、しかしながらcleanを実行すると全てのframeworkがビルドし直しとなって分割ビルドの恩恵が得られません。

特にCocoaPodsを使っていると全てのpod管理下のframeworkが再ビルドとなるため大変効率が悪いです。

これらを踏まえて対処法を考えてみました。と言っても大したことは出来ないのですが、

  • 定期的にビルドタイムをチェックする環境を用意する
  • CocoaPodsをやめてcarthageを使用する
  • microframeworkをやめる、どうしてもmicroframeworkを行うのであればcarthageと併用する

ビルドタイムのチェック方法は https://thatthinginswift.com/debug-long-compile-times-swift/ に記載がありますが、Other Swift Flags-Xfrontend -debug-time-function-bodiesを追加してビルドし、ビルドレポートを見ればOKです。結果はpbpaste | egrep '\.[0-9]ms' | sort -t "." -k 1 -n | tail -10などで整形すると見やすくなります。100msを超えている関数があれば手を打つ必要があるかもしれません。

CocoaPodsですが、手元で全てのframeworkをビルドしようとするためcleanした際の無駄が多いです。carthageを使えば最初にビルドを一回行って後はそれを参照して使いまわすだけ、という風にできます。ただしcarthageは最初のビルドがやたら長く、CocoaPodsを使った場合より5倍以上遅い?と言う問題があるのでその点は注意が必要です。

microframeworkを辞める論についてはおそらくいちばん賛否両論議論があるところかと思いますが、少なくとも殆どの場合、開発中はコードを使いまわす回数と時間よりXcodeをcleanしてビルドし直す回数と時間のほうが支配的であると信じています。Xcodeがちゃんとしてさえいればベストプラクティスに従ったほうが良いのでしょうが、そのようなことは伝統的にないので、ベストプラクティスにこだわらずビルドを高速化するために一つのframeworkにまとめるのも悪くはないのではと思っています。
ただしcarthageと併用できるのであれば、一度ビルドしたmicroframeworkを使いまわすメリットが享受できるので良いかもしれません。その場合、microframework側はコードベースがある程度安定している必要があります。さもなければ何度も何度もcarthage updateを走らせ直して結局時間がかかることになります。

結論

いろいろ考えてみましたが、頑張ってビルド高速化するより、新しいビルドマシンを増設したほうが結果的に良いかと思います\(^o^)/

2016/12/01 追記

Qiitaにより詳細で素晴らしいまとめがあったのでそっちを見ておいたほうが良い気がします(´・_・`)

全体的に見て型キャストとかワンライナー(とそれを誘発する演算子等)による途中の型推論が劇的に遅い原因のようですね。まぁ来年ぐらいまでにはclangが賢くなって直ってるのではないでしょうか・・・多分・・・

2016年11月14日月曜日

UNNotificationAttachment.init(identifier: String, url: URL, options: [AnyHashable : Any]? = nil)に拡張子のないURLを渡す際の注意

iOS 10で導入されたUserNotifications.frameworkは大変便利ですが、落とし穴が早速幾つか見つかっておりますのでご紹介いたします。
参考: iOS 10で画像つきのNotificationを配信する - Qiita

表題にありますUNNotificationAttachment.init(identifier: String, url: URL, options: [AnyHashable : Any]? = nil)ですが、第二引数のurlに画像や動画などのメディアのURLを渡してUNNotificationContentに付与すると言う使い方をするのが一般的かと思います。

このときどうやらUserNotifications.frameworkはurlのpathExtension、要するに拡張子の情報を利用してメディアの種類を判別しているようで、以下のような状況が発生すると実機でのみUNNotificationAttachment.initの実行が失敗してnilが返却されます。

  • 第二引数のurlに拡張子が付与されておらず、かつoptionsに[UNNotificationAttachmentOptionsTypeHintKey: "<当該URLのメディアの適切なMIME Typeを表す文字列>"]が指定されていない場合。
  • または間違った拡張子やMIME Typeが指定されている場合。

なおシミュレータでは問題ありません。いきなり実機に持っていって困るということが有るかと思いますので十分ご注意ください。

対処法は2つあります。

  1. URLに適切な拡張子を付与する
  2. optionsに[UNNotificationAttachmentOptionsTypeHintKey: "<当該URLのメディアの適切なMIME Typeを表す文字列>"]を付与する

何れにせよURLが指し示すメディアの種類が正確にわかっていないと問題になるため、その点は注意が必要です。

2016年10月4日火曜日

Q. ATS を Debug ビルドでだけ無効にしたいのですが...

A. こちらの内容に従えば一発です。

要するにBuild Phaseにビルドスクリプトを追加してそこでPlistBuddyを使って値を書き換えましょうと言う作戦です。

もうちょっとマシな解説

普段、Info.plistの設定内容をConfiguration毎に書き換えたい場合は、たいていよくやるのがxcconfigファイルを以下のように用意して、
APP_BUNDLE_NAME = MyApp_Dev
でもってInfo.plistに対して
Bundle Display Name = ${APP_BUNDLE_NAME}
こんな風に書いておけばビルド時に自動的にXcodeが環境変数による置換処理を行ってくれる、というのを使うのですが、まいったことにATSの設定を司るNSAllowArbitraryLoadsはString値ではなくBool値でして、このInfo.plistに対するXcodeの環境変数置換処理はString値(と、確かNumber値)にしか使えないというオチがあります。仕方がないので最初に説明した方法が最善になるかと思います。Info.plistファイルをConfiguration毎に用意する方法もありますが、大概そっちのほうが設定のメンテナンスが面倒になるのでオススメしません。

2016年10月3日月曜日

ATS の AVFoundationに対する 例外条項の注意点

2016/10/03段階でのATSを有効にする際の覚書です。基本的には全てTLS 1.2以上をサポートするhttpsにしてしまえばOKですが、例外条項としてAVFoundationのStreamについてはhttpでもよいと例外条項が定められています。

https://developer.apple.com/videos/play/wwdc2016/706/?time=324

これについては設定不要で自動的に適用されるようにWWDCのビデオ上では見えますが、実は落とし穴があり、この例外条項はiOS 10以降でのみしか適用されません。iOS 9については実はAVFoundationのStreamについてATSが完全に適用されているようで、httpの動画をStreamingしようとしても失敗してしまうので注意が必要です。

2016/10/03 16:45 追記
こちらXcode 7.3.1でビルドしたバイナリにて調査した内容ですので、SDKのバージョンが異なるXcode 8.0以降でビルドしたバイナリであればiOS 9.x系でもAVFoundationのStreamについてATSの例外条項が適用されてhttpで通信できるようになるかもしれません。ただ紹介した参照元のWWDCのビデオを見ても分かる通り、基本は例外を考えず全てhttps化するのが良いとされているため、ビデオストリームについても可能であれば全てhttps化するほうがトラブルがないかと思います。