業務系と、ソーシャル系と、エンジニアと

気がつけば1年以上放置していた・・・。
適当に何か書く。


私は新卒でシステム開発会社に入社し、主にB2Bシステム開発に携わってきた。
B2Cの割合は2割にも満たないくらい。
案件の引き合いから要件定義、見積り、設計、開発、テスト、納品と一通りの流れを経験したあたりで、最初に入社した会社の将来性に疑問を持ち転職。
転職先は知り合いのエンジニア2名が建てた会社で、それぞれ社長と取締役。
パートナーやアルバイトはいたが、社員としては私が第一号であった。
会社としてのビジョンはしっかりとあり、組織が育っていく過程を見たかったのと、育てていく経験をしたかった。
ただ、当時はまだ会社としては準備段階で、業務委託エンジニアとして外へ出て、月単価で売り上げを上げつつ自社サービスを開発している状況だった。
そこで、私が行き着いた職場が所謂ソーシャルゲームの開発現場であった。


業務系がメインとは言えWEBシステムの業界に数年居たわけで、当然ソーシャル業界の動向は業務知識としてある程度把握しているつもりだった。
実際に入ってみて、予想通りソースコードは継ぎ接ぎだらけで汚く、メンテナンス性は最悪だしコメントも一切ない。
今までの感覚で言うと、こんなものは到底お客様への納品物としては成立し得ない代物だった。
ただ、各々の現場において最優先とされるものは異なる。
ソーシャルゲームの現場では、とにかく競合他社との争いが激しくスピードのある開発が求められた。
色々思うところはあっても、まずは耐えて実績を上げ、現場において一目置かれる存在になるべく動いた。
実績を伴わない発言は「意見・提案」ではなく「文句」と受け止められてしまうからだ。

  • スクリプトを組むことにより日々のリリース手順の簡略化
  • インパクトで開発効率を向上させられるノウハウの提案
  • プロパー/業務委託問わず周りのエンジニアへの知識の共有
  • トラブル時の対応
  • 企画サイドとの折衝(あえて歯に衣着せぬ物言いをすることも)

これらは特にソーシャルならではという物はなく、今までの経験から得たものだったり自身のスタンスなのだが、
現場における自身の価値の向上を図り、それに適したキャラクターを演じ、地道に積み重ねることにより、それは実った。
業務委託としての自身の価値が高まると、自ずと契約延長時に単価の交渉が入る。
ここで、自らが直接交渉する事に面白さを見出す。
一旦、社長に相談を持ちかけた。
  私がこの現場でやってきた事が一定の評価を得ている。
  これにより単価が上がった場合は何かしらの形で還元されるのか。
社長の答えはNOであった。
理由は色々あったが詳細は省く。納得のいく理由だった。
自身のスタンスなどを告げていく中で、社長のほうから、そこまでの考えがあるならフリーランスになるか自分で会社建てるなどするほうが合っている。
と言われた。(「これ以上面倒見切れんよ」の意と捕らえたが)


ひとまず、自身で交渉を行い、こちらの条件を飲んでいただく形でフリーランスとして現場に残ることが決まった。
転職後の在職期間は1年ほどであったが、あたたかく迎え入れていただき、また、私のエンジニアとしてのキャリアを尊重し送り出してくれた。
短い期間であったが、組織が育っていく過程も垣間見ることができた。
現在は、外に出ていた社員も事務所に戻り、自社サービスの開発や受託案件の開発を行っていると聞く。
心から応援したいし、またご縁があれば別の形でご一緒できるとするならばこんなにうれしいことはない。


さて、前置きが長くなった。
業務系とソーシャル系、基本的にはものつくりとしては何ら変わるところは無いと思っている。
ソーシャルだと「スピード感のある開発」と言う文言が散見されるが、業務系であっても短納期のわりにそれなりの工数の案件(修羅場)も多く経験してきた。
正直、失敗したり開発が間に合わなくても自分らが痛手を受けるだけで業務系で言うところの「お客様」へ損害を与えるわけではないのでむしろ楽とさえ感じた。


ただ、常に違和感として感じていたのは、設計書(といってもOfficeドキュメント数枚程度の簡素なものだが)を作成するのが企画サイドで、それを元にエンジニアが開発を行うというスタイルだ。
なぜなら、業務系の感覚だと、お客様の要望(やりたいこと)を聞き、それ以降はすべてエンジニアの範疇だからだ。
その中で、要望を解釈して明確な目的(要件)として落とし込み設計を行う事ができ且つ開発工程のどのタイミングでどのような人員をアサインすべきかを判断できるもの、あくまで実装を担当するものとで一般的には(日本においては)エンジニアは区別される場合が多い。
営業的には、前者をシステムエンジニア(SE)、後者をプログラマー(PG)と呼び区別することが多い。
また、同じエンジニアであっても前者と後者とでは求められるもの、範囲が大きく異なる。
*1


話が逸れたが、現場の実態としては、上記で言うところのPGが殆どで、開発と言うものを知らない企画が作った設計書から形にすることは本来であれば難しいはずであった。
ただ、ソーシャルゲームということもあり「この機能はあのゲームで言うところの○○か」というように解釈することで各々対応していた。

しかし、この違和感はその後大きな形で打撃となって押し寄せてきた。
ソーシャルゲームは新規タイトルの開発であっても既存タイトルの横展開での開発が多いが、横展開ではないチャレンジングなタイトルの開発が現場で企画されており、私がそのサーバーサイドエンジニアとしてアサインされた。
そこで目の当たりにしたのは、企画のみで進められてきたプロジェクトの顛末。
サーバーサイドエンジニアとして、担当範囲としてまずはフロント(ゲーム画面)との値の入出力の設計やデータベースのER作成から入るわけだが、UIも明確に決まっていない、モックも殆どできていない、なのにリリース予定日だけは決まっているという状況であった。
UIが決まらなければフロントとのIO仕様を設計することなどできないし、ER図作成もできやしない。
一発ものであれば見切り発車で着手してもいいかもしれないが、今後、このタイトルをベースに横展開をしていく想定もあるのだから半端な設計はできない。
ここをしっかり設計するか否かで、今後の運用・新機能開発コスト、さらには横展開タイトルのコストに何重にも重くのしかかってくる。
「これがソーシャル系の開発だから」や「何か起きたらマンパワーでなんとかする」と言ったスタンスは程度が低い精神論・根性論を掲げる侮蔑的体育会系思考だ。
優秀なスポーツ選手は「いかに楽をして安定した成績を出すか」を考え、頭を使い、長期的に自身を安定した状態とするべくメンテナンスしていくことに努める。


プロジェクトの現状を受け、現場の責任者にはっきりと言った。
「このプロジェクトはまだ開発に取り掛かれる段階ではない」と。
その上で、

  • 開発を行う上で企画段階から必ずエンジニアを参画させておく必要がること
  • そこにアサインするエンジニアについては、単にプログラミングの実績のみで見るのではなくB2BでもB2Cでもどちらでもいいからゼロの状態から、絵に描けてもいない餅を形にしてきた経験のあるものをアサインすること

などを伝えた。
これを受けてかどうかは私の知るところではない(理由のひとつにはなっているかもしれないが大きくは別の理由であると想定している)が、程なくしてこのプロジェクトの仕切りなおしが決定し、チームは一旦解散となった。


ものつくりは、企画やエンジニアなど各セクションの理想のぶつけ合いだ。

  • 企画の理想に対し、エンジニアは限られた時間とリソース等を鑑み、現実を突きつける
  • エンジニアはエンジニアで、まずは、ものをつくる上での最も理想とする工程を描く
  • クリエイターは納期いっぱいを使って質の高いものを創り上げる
  • etc...

これらを受けて、リリースを最優先するならば機能の段階リリースや、今後に影響を与えない範囲で開発工程を一部重複で進めるなどの方法を模索・検討・提案していく。


このような音頭を取るのに最も適しているのはエンジニアだ。
誤解を恐れずに言ってしまえば、ものつくりの現場において最も「強い立場であるべき」なのはエンジニアだ。
幅広い知識を持ち、全体を俯瞰し、企画が語る理想から明確なゴールを導き、メンバー全員に認識を共有し、プロジェクトの進行に沿って然るべきポイントで必要な要員をアサインし、ゲームであれば画像やBGMなど素材の状況も把握し、最終的にそれを形とする。
これらはすべてエンジニアの役割だ。
基本的にはレイヤー毎に分担することになるだろうが、中には一人ですべてをこなしてしまうケースもあるかもしれない。
もちろん、様々な画期的なアイデアを挙げる企画や、ストーリー性のあるものであればライターであったり、その世界観を考慮した画像やBGMを創るクリエイターも重要な役割だ。
ただ、これらをまとめ、プロジェクトの進行管理を行うのは、何も無い状態からひとつのシステムとして形にする工程を知っているエンジニアが行うべきだ。
ここまでいうとエンジニア至上主義と受け取られかねないが、現場とリソースと時間その他もろもろを鑑みてプロジェクトの各ポイントで何が揃っているべきか、何が決定しているべきかを把握・判断することができるものであれば良い。
それに最も近いのが、上述のような経験のあるエンジニアであることが多いというだけ。


今の現場は数ヶ月後の契約満了をもって去る。
(現場とケンカしたとかそういう類ではない)
次の身の置き場は多方面で検討中だが、もう一度、というか引き続き、ソーシャルの現場で戦ってみたいという思いが強くなってきた。


すでにいくつかアクションはしている。
果たしてどうなるか、何が起きるか楽しみだ。


*1:個人的には、このようにエンジニアを区別する事には違和感を感じるが詳細は割愛

AndroidでTwitterクライアントを作成(OAutn認証、PINコードを自動取得)

AndroidTwitterクライアントアプリを開発する際、Twitterの認証後にブラウザ上に表示される
PINコードをAndroid側に知らせる必要があります。
その際、表示されたPINコードをEditTextに入力してもらうのは面倒なので
ブラウザ上のHTMLから自動取得するサンプルを作ってみました。
カスタムURLスキームのコールバックURLを指定する方法でも実現可能かと思われますが、
こちらは本記事の最後に補足として記述しています。


AndroidのブラウザコンポーネントであるWebViewには、タイトルを取得するメソッドはありますが
表示されているページのHTMLソースを取得するメソッドはありません。
今回、HTMLソースをAndroid側へ渡すための方法として
WebChromeClient#onJsAlert()メソッドを利用しました。
これはjavascriptのalertをAndroid側でハンドリングするための仕組みですが
当該メソッドをオーバーライドすることによりHTMLソースを取得する手段として利用することができます。


ちょと長いですがサンプルソース。Twitter4jを使用しています。

package sample.twitter.oauth;

import org.apache.commons.lang3.StringUtils;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.auth.RequestToken;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.util.Log;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

public class TwitterOAuthSampleActivity extends Activity {
	private WebView webView;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		Twitter twitter = new TwitterFactory().getInstance();
		RequestToken requestToken = null;
		try {
			requestToken = twitter.getOAuthRequestToken();
		} catch (TwitterException e) {
			Log.e("Exception", "", e);
		}

		webView = (WebView) findViewById(R.id.webView);
		webView.setWebViewClient(new CustomWebViewClient());
		webView.getSettings().setJavaScriptEnabled(true);
		webView.loadUrl(requestToken.getAuthenticationURL());
		webView.setWebChromeClient(new CustomWebChromeClient());

	}

	private class CustomWebViewClient extends WebViewClient {
		private ProgressDialog progress;

		public CustomWebViewClient() {
		}

		@Override
		public boolean shouldOverrideUrlLoading(WebView view, String url) {
			view.loadUrl(url);
			return true;
		}

		@Override
		public void onPageStarted(WebView view, String url, Bitmap favicon) {
			// 格好をつけるためにスピナー型プログレスダイアログを表示
			if (progress == null) {
				progress = new ProgressDialog(view.getContext());
				progress.setMessage("通信中");
				progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
			}
			progress.show();
		}

		@Override
		public void onPageFinished(WebView view, String url) {
			progress.hide();

			// HTMLソース上のpinコードを取得するためのJavaScript
			String script = "javascript:var elem = document.getElementsByTagName('code')[0]; if(elem) alert(elem.childNodes[0].nodeValue);";
			view.loadUrl(script);
		}

	}

	// JavaScript:alertをAndroid側でハンドリングするための仕組みである
	// WebChromeClient#onJsAlert()メソッドをオーバーライドして
	private class CustomWebChromeClient extends WebChromeClient {

		@Override
		public boolean onJsAlert(WebView view, String url, String message,
				JsResult result) {
			// とりあえずAlertDialogでPINコードを表示し、ボタン押下によりアプリ終了
			if (StringUtils.isNotEmpty(message)) {
				AlertDialog.Builder builder = new AlertDialog.Builder(
						view.getContext());
				builder.setMessage(message)
						.setTitle("pin")
						.setPositiveButton("OK",
								new DialogInterface.OnClickListener() {

									@Override
									public void onClick(DialogInterface dialog,
											int which) {
										Activity activity = (Activity) getCurrentFocus()
												.getContext();
										activity.finish();
									}
								});

				AlertDialog dialog = builder.create();
				dialog.show();
			}

			result.confirm();

			// アラートダイアログをこのメソッド内で処理したか
			// falseを返すとAndroid APIによるデフォルトのアラートダイアログが表示されるため、今回はtrueを返す
			return true;
		}
	}
}

※追記
上記コードではProgressDialogのインスタンスを使いまわしてページ読み込みの度にshow()とhide()を読んでいますが
このままだとActivityをfinish()した際にExceptionが発生してしまいます。
finish()の前に、ProgressDialog#dismiss()を呼び出す必要があります。


layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <WebView
        android:id="@+id/webView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />

</LinearLayout>

WebViewClientとWebChromeClientをそれぞれ拡張し必要な処理を追記したものをWebViewオブジェクトに設定しています。

HTMLを解析しPINコードを取得

現状、Twitter認証後のPINコード表示箇所のHTMLは以下のようになっています。

<div id="oauth_pin">
  <p>
    <span id="code-desc">val90 devに戻り、次のPINを入力して認証を完了してください。</span>
    <kbd aria-labelledby="code-desc"><code>xxxxxxx</code></kbd>
  </p>
</div>

codeタグ内にPINコードが記述されています。
よって、codeタグ要素の内容をAndroid側で取得するようにします。
URLからJavaScriptを実行する仕組みを利用します。
ページ読み込み完了時、HTML内にcode要素があるかを調べ、code要素が存在した場合その内容をalert関数に渡します。

// HTMLソース上のpinコードを取得するためのJavaScript
String script = "javascript:var elem = document.getElementsByTagName('code')[0]; if(elem) alert(elem.childNodes[0].nodeValue);";
view.loadUrl(script);


上記JavaScriptでcodeタグが見つかりalert関数が呼ばれると、Android側のWebChromeClient#onJsAlertメソッドに制御が移ります。
第三引数のStringオブジェクトmessage変数に、JavaScriptのalert関数に渡された値が設定されています。
今回のサンプルではAlertDialogでPINコードを表示するのみでアプリケーションを終了していますが、
ここにAccessTokenの取得、保存などの処理を実装すれば良いでしょう。

@Override
public boolean onJsAlert(WebView view, String url, String message,
		JsResult result) {

	// とりあえずAlertDialogでPINコードを表示し、ボタン押下によりアプリ終了
	if (StringUtils.isNotEmpty(message)) {


〜 略 〜
	

	}
	
	result.confirm();

	// アラートダイアログをこのメソッド内で処理したか
	// falseを返すとAndroid APIによるデフォルトのアラートダイアログが表示されるため、今回はtrueを返す
	return true;
}

注意点としては、万一Twitter認証画面のHTMLソースが変更され、codeタグ内にPINコードが記述されなくなるような
事があった場合はAndroidアプリ側も改修する必要があります。




※補足
今回はHTMLソース上のPINコードを自動取得するための参考を示しましたが、
Twitter認証の自動化(PINコード入力の煩わしさを解消する)という目的であれば
カスタムURLスキームを用いる方法でも実現できるかと思います。
たとえば、AndroidManifest.xmlファイルのintent-filterにおいて


などと設定し、Twitter認証時のコールバックURLを以下のように指定すればアプリケーション側で
oauth_verifierを取得することができるのではと思われます。
・当方では未確認
・コールバックを使用する場合はTwitter側でアプリの管理画面でコールバックURLに何らかのURLを指定する必要がある
・管理画面でcallback urlを入力しておかないと、oauth_verifierが渡ってこない。

mytwitterclient://oauth/callback

参考
http://developer.android.com/guide/topics/manifest/data-element.html



今更ながらシュタインズゲートにはまる

アニメ版を録画したまま今までずっと放置していたシュタインズゲートを先日ようやく見終えた。
感想:

めちゃくちゃ面白いやんけこれ。

特に牧瀬紅莉栖のキャラが個人的ドストライク。
てことでメディアミックスされてる関連商品を見てみたら紅莉栖視点のライトノベル版があるということで早速購入。






Amazonでの評価も概ね高評価の様子。
さくっと3冊とも読み終えた。
うん、間違いなかった。
紅莉栖好きならまず買って損をしないと思われる。
個人的にはピンポイント過ぎるけど3巻287ページの3行目が一番好きだ。
他にも紅莉栖いつ頃から岡部の事を好きになったのかとか具体的にどういうところがすきなのかとかあのシーンでの紅莉栖の心情はこうだったのかとか見所はたくさん。
アニメでは表現されていない紅莉栖とフェイリスの接点とか秋葉原駅のホームまで行ったはずの紅莉栖がなぜ数時間も後になってα世界線へ戻る直前の岡部が居るラボへ戻ってきたのかとか。
アニメ版最終話のその後の話もあり。
この辺の話はどうやらドラマCD版と被っている様子。
次はこちらを購入してみようと思う。






ノベルの方は3巻でひとまずアニメ版最終話+αまで描かれた訳だけど続編もまだ出るようで非常に楽しみ。 となると必然的にゲーム版にも興味を持つわけだけど、こちらはPS3版の発売まで待ってみようかと思う。






iPad2のHDMI出力をPCでキャプチャする

iPad2HDMIミラーリング出力をPCでキャプチャしてみた。


構成は以下の通り。
※あくまで当方の自作PC環境での動作報告であって、この記事を参考にしたがうまくキャプチャできないなどの問題が発生しても一切の責任は負いかねます。


iPad2
-> Apple純正digital AV Adapter
-> PLANEX HDMIセレクタ HDMI-SW0401(ゲーム機との併用の為)
-> 1入力2出力 HDMI分配器 スプリッター(モニタとPCへ出力する為)
-> ハイパーツールズ HDMI to HDMI ビデオスケーラー CP-298H
-> PC(キャプチャボードはDM626 H3)


途中でCP-298Hを挟んでいるのは、iPad2HDMI出力は1080pであるのに対して、DM626 H3は1080iまでしか対応していない為、
CP-298Hによって、キャプチャボードへの出力を720pにダウンスケールしている。
また、iPad2HDMI出力にはHDCP暗号化がかかっているので、キャプチャボードはDM626 H3等のHDCPに対応しているもの(ドリキャプ DC-HA1など)にする必要がある。
自分の環境はWindows7 64bit且つメモリ4GB超の環境なので、DM626 H3にした。
この辺の64bitやらメモリ4GB超云々の話はきちんと自分のPC環境とマッチしたキャプチャボードを選ぶ必要があるので、良くわからなければ検索するなどして調べてから慎重に購入するべき。


あるいは、途中にハイパーツールズ Game Switch PS3-S201Aを挟むやりかたでもいけるかもしれない。
※当方では未確認


Apple純正のHDMI出力アダプタ


CP-298H本体

CP-298説明書


キャプチャの様子(純正ソフト使ってないのでxsplitで・・・普段はアマレコ使用)

 考え方

なんだかんだと自分の考えをぐだぐだと書いているけども、


考え方は「正誤」ではなくてその場面での背景なども含めた上での「良し悪し」で都度自分自身で判断すべき。


自分がここに落書きしているのはあくまでひとつの考え。
参考になる部分があれば判断材料の一つとして加味すれば良いし、
そうでなければ「こういう考えの人も居るんだな」程度で十分。


 ネットとリアル

ここ最近、今更ながらネット上でのコミュニケーションについて考えることが多いので思うところを適当に書いてみる。


ここで挙げるネット上でのコミュニケーションとはあくまで趣味を目的としたエンターテインメントとしてのネット利用の場合で、
特定のスキルアップを目的とするようなケースは対象外とする。

「ネットに逃げる」のはありか?

ネットに逃げてどっぷりはまってそのまま帰ってこないのはまずいけど、
リアルあっての息抜きやはけ口としてのネットの使い方は十分にありだと思う。
そして回復したら、「ただいま、現実!」すればいい。

ネット上での対人関係

ネット上でもまた別の「対人関係」が出てきてこれまた面倒だったりするけど、
乱暴に言ってしまえばネット上で知り合った人々はリアルよりもぞんざいに扱って良いと思う。
それこそ利害関係ありきで。
もちろん、そこから「信頼」に発展してリアルの繋がりになる事もあるけれども、
こう言った例はあくまで偶然の副産物と考えるべきで、それを目的とするのは好ましくないと思う。

ネット上で「失敗」したら

ネットの世界はリセットしやすい。
それを逃げだと感じる人も居るけど、リアルの自分にゆとりを持たせる目的であれば十分に良い選択肢。
さらに、その「失敗」の原因をリアルに持ち帰ることができれば、得るものは大きい。

個人的なネット感

自分の場合はネット全体を一つの「道具」と見ている。
よって、そこに居る人達もそれを構成する一つのパーツに過ぎない。
ものすごく乱暴な言い方だけれども、必要であれば留めようとするし、不要であれば切り捨てる。
言うまでも無く、自分自身が切り捨てられる覚悟も当然できている。
ネットもリアルも、すべての人に好かれることなど不可能。
いかなるアイドルであろうとアンチは居る。
付き合うべき人の取捨選択を上手く行い、ネット上は自分にとって「気持ちの良い場所」としたい。