2013年12月31日火曜日
2013年を振り返って
自分の関わっている業界で感じたことを中心にこの1年を振り返ります。
今年は、プロダクトの開発に関わるのかなぁ、と思っていましたが、諸事情あり結局SIの1年間となってしまいました。
この1年で、クラウドは普及というより、当然の選択肢となったと感じています。
また、お客様から単一のサービス(やパッケージ)を導入すれば何とかなるレベルのものではなく、様々なサービス(オンプレミスだろうがクラウドだろうが関係ない)を組み合わせるケースが増えてきました。
2014年、確実に言えることは「導入がより複雑になる」ということです。
プログラミングするための設計よりも、様々なサービス・プロダクトを連携した場合の図を描くことができる人がより必要になっているのではないでしょうか。
大手企業であれば、既存のシステムと連携することが必須です。ここでいう連携とは、システム的に連携する必要があるということではなく、システム的に連携する価値があるかどうかという観点からお客様にベストな方式を提案できることが大事です。
特に、連携するサービス間で何からのインシデントが起きたときの設計は、担当者のスキルがもっとも現れるところではないでしょうか。
「一見、サービスインしました」といって、インシデント・オペレーションについて、何も考慮せずにシステム連携した場合の現場の悲惨さは簡単に想像できるでしょう。
また、プロダクト・サービスの淘汰も来年から顕著になってくると思われます。
特に大企業向けのプロダクトは、勝ち組、負け組がはっきりしてくるかと。
以上、2013年年末時点での記録です。
みなさま、2014年もよろしくお願いします。
2013年10月6日日曜日
AWS S3に画像をサムネイル表示するプログラムをscalaで作ってみた
コーディングしないと、お客様への提案内容(特に技術的に可能かどうか)や見積もりのカンが鈍る。技術は日進月歩で、何もしないとお客様にまともな提案ができない。
今回のS3に画像をサムネイル表示する件も、あるお客様との打ち合わせがきっかけだ。
AWS S3に画像をアップロードしたときに、何でS3にこんな機能ないんだろう?って思った。
当初はscalaまで使ってコード書くつもりはなかったんです。
pythonのs3cmdと、アルバム作成するソフトを組み合わせれば、シェルを組めば実現できると思う。あとrubyを使ってもいいですね。
ただ、アルバム作成ソフトって、IE6に対応してないんです。JavaScriptがもうIE8以上しかダメ。お客様社内の端末はIE6なので、シンプルなHTMLでUIを作った方がいいと思った。(別にJavaScript凝ってもいいけど)
ってことで、早速深夜作業の待ち時間に作成してみた。
環境は以下の通り
- scala 2.10.2
- sbt 0.12.3
ソースの説明です。
まず、AWS SDK JavaのAWS S3クライアントを作成する。
//create AmazonS3Client instance
val s3 = new AmazonS3Client(new ClasspathPropertiesFileCredentialsProvider);
val region = Region.getRegion(Regions.AP_NORTHEAST_1);
s3 setRegion region
次に、AWS S3のバケッド名を設定する。
(ここでは、バケット名をkzsampleとしている。)
//Get Objects in a bucket
val bucketName = "kzsample";
val objectListing = s3 listObjects(new ListObjectsRequest withBucketName bucketName)
S3のバケットからJPEG画像のパスをリストで取得する。
(scalaだとここが非常にシンプルなロジックでいいですよね。)
//Set Jpeg Files in jpegList
val jpegList = new java.util.ArrayList[String]
objectListing.getObjectSummaries().filter(p => p.getKey().endsWith(".jpg")).foreach(q => jpegList.add(q.getKey()))
VelocityテンプレートにS3から取得したパスを埋め込む。
テンプレートのパスは、templates/order.vmとしています。
//Velocity
Velocity.init()
val context = new VelocityContext()
context put("jpegList", jpegList)
val sw = new StringWriter()
Velocity getTemplate("templates/order.vm", "UTF-8") merge(context, sw)
テンプレートのサンプルはこんな感じ。
VelocityでparseしたHTMLをS3にアップロードするオブジェクトに変換する。
val is = new StringInputStream(sw.toString())
val metadata = new ObjectMetadata()
metadata setContentEncoding "UTF-8"
metadata setContentType "text/html"
最後に公開権限をつけて、S3にアップロードする。
val is = new StringInputStream(sw.toString())
//Upload html file to S3
val putRequest = new PutObjectRequest(bucketName, "html/sample.html", is, metadata)
putRequest setCannedAcl CannedAccessControlList.PublicRead
s3 putObject putRequest
ということで、できたサンプルがこれです。
テンプレートのHTMLのデザインをもっと格好よくすれば、応用が効きますね。
HTML5とか....
参考までに、ソースはこちら
2012年9月16日日曜日
playframework1.2のJobでハマったところ
個人的には、playframework2.0系であれば、プログラマが自由にトランザクション範囲を定義することができるため、今後は2.0を使っていきたいが、1系のアプリケーションをメンテする必要がある場合は、マルチトランザクションを実装しないといけない場合があるだろう。 playframework1系でハマったところを備忘録としてメモっておく。
今回、playframework1系で実現したい機能は以下である。 playframeworkのJob機能を使って、複数のバッチジョブを順に実行したり並行して実行するために、ジョブ制御テーブルをDBにもち、各バッチジョブの開始、終了時にジョブ制御テーブルを更新する。
まずは、playframeworkのJobクラスを拡張する。
トランザクションがネストしていないので、トランザクション境界にはJPAPlugin.startTx(false)とJPAPlugin.closeTx(false)を用いることがポイントだ。
業務ロジック用のJobはコンストラクタに設定してあげればよい。
public class JobInvoker() extends Job{
/**
* 業務処理をするJobクラス
*/
private Job<JobResult> job = null;
/**
* コンストラクタ、業務処理するJobクラスを設定する。
* @param job
*/
public JobInvoker(Job<JobResult> job){
this.job = job;
}
/**
* Jobの実行状況を制御するJobStatusManagerを用いてステータスを変更する。
* @see play.jobs.Job#doJob()
*/
@Override
public void doJob() throws Exception {
//この段階で既にトランザクションが開始されている。
JobStatusManager manager = new JobStatusManager("JobA");
try {
if (manager.isExecutable()) {
//DBのテーブルにあるステータスの値を「実行前」から「実行中」に更新する。
manager.startJobStatus();
manager.commit();
//ここでcloseTxするか、DB.getConnection().commit()しないとDBに値が更新されない。
JPAPlugin.closeTx(false);
//ここから業務処理用のジョブの開始
//業務処理用に新たにトランザクションを開始する。
//doTask()メソッドがコンストラクタに設定したJobを呼び出す。
{
JPAPlugin.startTx(false);
doTask();
JPAPlugin.closeTx(false);
}
//ステータス更新のためのトランザクションを開始する。
JPAPlugin.startTx(false);
//DBのテーブルにあるステータスを「実行中」から「完了」に更新する。
manager.completeJobStatus();
manager.commit();
}
} catch (Exception e) {
//異常時はDBのテーブルにあるステータスを「実行中」から「異常終了」に更新する。
manager.failJobStatus();
manager.commit();
Logger.error(e, "%s failed !", this.getClass().getName());
} finally {
manager.close();
if(JPA.isInsideTransaction()){
JPAPlugin.closeTx(false);
}
}
}
/**
* コンストラクタに設定したジョブを呼び出して結果を取得する。
* @throws ExecutionException
* @throws InterruptedException
*/
protected void doTask() throws Exception {
Promise<jobresult> promise = job.now();
if(!promise.get().isSuccess()){
Logger.error(promise.get().getException(), "Error", null);
throw promise.get().getException();
}
}
}
また、上記のように実装した場合、設定ファイルのapplication.confもいくつか追記しないといけない。
- db.pool.maxIdleTimeExcessConnectionsを記述しないとDBのコネクションが解放されずに増え続け、一定時間後にPersistanceExceptionが発生する。
- db.pool.minSizeは、play.jobs.poolよりも多く設定しておく。そうしないとコネクションがタイムアウトしましたというPersistanceExceptionが発生する。
#Jobに割り当てる最大スレッド数の設定 play.jobs.pool=10 #DBの設定 db.pool.timeout=10000 db.pool.maxSize=40 db.pool.minSize=20 db.pool.maxIdleTimeExcessConnections=10
やはり仕事で使う場合は、マルチトランザクションは必要だ。また、常駐ジョブは一定期間の安定テストを行う必要がある。playframeworkでマルチトランザクションでバッチを起動するなら上記設定内容だけは覚えておきたい。
2012年8月25日土曜日
クラウド温泉3.0 に参加して(2)
<プログラマのための代数入門2 Monadへの道>
中村(@nakayoshix)さんに、Monadを説明していただきました。
といっても1時間でMonadの説明までたどり着くのは無理があるらしく、その前の群の説明が中心でした。特にルービックキューブを使った「逆元」「非可換」の概念は分かりやすかった。
Monadに関しては、日本語のWikiでは、十分な説明がないことが分かりました。
ただ、それをプログラムで実現する場合、IOとか外部の環境を考慮に入れる必要がある。IOなどの環境を包括してくれるモナドがどこまで使い物になるのだろうか。そこは、自分で検証する必要があると感じた1時間でした。
<「基礎から見直すTX処理〜A Critique of ANSI SQL Isolation Levelsを再読する」>
@okachimachiorz1 さんの発表。今回のクラウド温泉で最もインパクトが高い発表でした。
トランザクションについて、ANSIのSQL規格ではまだ不十分。理想とするトランザクションがコンピュータで実現された状態を100とすれば、現在はまだ40くらいだそうだ。(根拠はないけど)
私は、ANSIで定義したトランザクション分離レベル(これの理解も中途半端)が常識だと思っていたので、しょっぱなから頭をうたれた。
発表は、「A Critique of ANSI SQL Isolation Levels」を読むための前提知識と左記論文の概要を説明していただきました。
もっとも大事なことは一貫性(consistency)であり、それを実現するため、原子性(atomicity)、独立性(isolation)が存在すると解釈しました。
トランザクション実行後の「何が正しいのか」という基準を明確にする必要があります。
当発表では「isolationはserialisableになればよい」「semantic violationでないこと」を正しいと定義していました。ただ、「serialisable」と「serialised」を誤解する人が多いそうです。(私もそうでした。)「serializable」とは、トランザクションが「serialised」された状態と同じ状態を意味的に最適化したものを意味します。
「serializable」にするために、どうやってrockしたり、snapshotをとったりするのがよいのかまでは理解できませんでした。「Transactional Information Systems」を読めば分かるそうです。(といっても敷居が高い)
ぼちぼち勉強していこうと思っています。
<本当は怖いDNSの話>
鈴木(@tss_ontap)さんの発表。
あまり詳しく書くことはできないが、DNSの仕組みが不十分で、あるドメインが乗っ取られることがあった事例を発表していただきました。SSLなどドメインを取得してアプリケーションを構築する場合、セキュリティとしてこんなリスクもあるということを抑える必要があると思いました。
その後、小樽商大の教室をお借りして、ディスカッションをしました。
浅海さんの発表をベースに、OOPと関数型を使ったアーキテクチャ、モデリングについて議論しました。業務寄りの部分は今まで通りOOPを使い、基盤よりの部分に関数型を利用すると上手く構築できるのではという内容でした。サーバのコア数が増え、C10K問題を考えると、並列プログラミングをするためには、関数型を使って並列処理が可能な基盤部分のアーキテクチャを構築できる人が重要になってくると実感しました。
自分としても、このような基盤構築に関わっていきたいし、このような基盤を使ったソフトウェア、システムを構築したいと思える2日間でした。今後の仕事には、まずscalaを使ってパイプラインプログラミングが実際に使いモノになるのか検証できたらなぁと思っています。
最後に、中村さんをはじめ、発表していただいたみなさま、参加者のみなさま、ありがとうございました。今後ともよろしくお願いします。
2012年8月22日水曜日
クラウド温泉3.0 に参加して(1)
8/18,19と @nakayoshix さん主催の「クラウド温泉3.0」に参加しました。
本来であれば、何らかのアウトプットを出さないとなぁと思っていたのですが、転職して間もないこともあり、アウトプットを出すことは諦めました。
この勉強会に参加する一番の理由は、コストパフォーマンスの高さです。東京でこのレベルの勉強会をやろうとしても、人が集まりすぎて、参加者間のコミュニケーションがとれないからです。
各セッションごとの感想を書きます。
<Monadicプログラミング・マニアックス>
@asami224 さんの発表。これからのハードウェア、ネットワーク環境の変化に伴い、scalaなどの新しい関数型言語の長所を活かすポイントが分かりやすく書かれています。
「関数型言語を使うと何が便利になるのか」、自分の答えは、さまざまな処理を「並列」で動かすための仕組み(パイプライン)が揃っているからだと考えます。
今まで、WEBなどの画面から非同期でジョブネットを実行して結果を返すプログラムを作る場合、各ジョブの状態をスレッドセーフにしたりデッドロックとかを考慮する必要があるため、非常に難しい実装になります。一方で、WEBから大量の非同期処理をキックした場合、JP1のようなジョブスケジューラソフトで制御できるものではありません。
それらを埋めてくれるのが、パイプラインプログラミングだと考えます。近頃は、APIなど外部システムの情報をマッシュアップするケースが増えてきています。これらの集計をWEBから効率よく実行するためには、パイプラインプログラミングが必須になってくると考えています。
<業務システムで使う型クラス>
@zenzengood さんの発表。 業務システムの上流工程で型クラスを使用してプログラミングして検証しましょうといった内容です。振舞や構造の変更部分に型クラスを使ってみれば、シナリオベースで検証できるからよいといった内容でした。ただし、オブジェクト指向のモデリングと比較して型クラスの何がメリットとなるのか、私には理解できませんでした。ただ、ワークフローの部分を型クラスとして、それ以外の概念は今まで通りオブジェクト指向のモデリングで対応すればよいのではないかと思いました。
<ぶいてく流スケーラブルアプリの作り方 2012>
@stakezakiさんの発表 RDBとKVSの長所を活かして、RDBだけでは捌ききれないデータの参照、更新に対応するための一つの案を示していただきました。KVSにはBarkleyDBを採用していました。また、RestなAPIでこれらのデータを参照、更新しています。これからの時代のサーバ構成、ミドルウェアの選択に関して考えさせられる発表でした。
一日目の感想は以上です。
二日目の感想は、また今度...
2012年7月16日月曜日
転職しても仕事の本質は変わらない
転職して、2週間が経った。
先週末、部署で歓迎会をしていただき、これで新入社員気分も吹き飛んだと思う。
30代半ば。今までの経験を見込まれての入社だ。以前の転職では、若さとポテンシャルを期待されていたが、さすがにこの歳になるとそうはいかない。
前職との最大の違いは、やはり「スピード」だ。7年ぶりに感じるベンチャーのやり方についていくのは大変だが、何とか食らいついているのではと自負している。
今回は、転職して感じる下記二点について書きたいと思う。
1. 「SIerからSaaSの会社に転職して自分の仕事内容が変わったか。」
2. 「自分のやりたい仕事ができているか。」
1.「SIerからSaaSの会社に転職して自分の仕事内容が変わったか。」と言われれば、答えは「No」だ。
アジャイル開発、Excelで設計書を書かない、リリース期間が短い...細かい違いを挙げればいくらでもあります。
ただ、「お客さまに価値ある仕組みを提案、提供する」という観点では、これっぽっちも変わっていない。一方、「社内関係者、チームメンバーと協力してソフトウェアを開発する」ということも変わっていない。お客さまのやりたいことを限られた期間、予算内で遂行するために徹底的に考えて提案する。ゴールを決めたら関係者に納得して動いていただく、という泥臭いことの繰り返し。これらは一切変わっていない。
だからこそ、「SIerでは言われたものを作るだけだけど、WEB系とかネット系で企画から携われるから転職したい」という理由で転職することは危険だと考える。まず、「SIerは、言われたものを作るだけ」という間違った認識が蔓延している。(これは、転職サイトとか人材紹介会社のプロパガンダのような気がする)お客さまのシステムを作るのに「要求仕様書に従って作ればいいんです」なんて言っているようでは、SIer失格だと思う。要求仕様書に対して提案するのもSIerの大事な役割だ。
2.「自分のやりたい仕事ができているか。」と言われれば、答えは「Yes」。
私にとって、「自分のやりたいこと」とは「お客さまに全うなシステムを提供したい」ということだ。
逆に言えば、どのようなシステム開発でも自社の都合(例えば、「内部統制で数回の社内の契約レビューをする必要がある」「ソースコードだと分からないから、決まったフォーマットで設計書を書いてレビューしなければならない」「バグ密度が○○/kstepsで基準に達していないから、強化試験を実施しなければならない」)といったお客さまの要望を無視した開発は勘弁してほしい。
お客さまを無視した自社都合な組織はいずれ衰退する。
お客さまの要望(納期、予算、品質)に合った手法を考え、最善の手段を用いてシステムを開発する。「多少のリスクがあっても新しい技術が何らかのメリットがあるなら、積極的に挑戦する」という文化で仕事ができることは満足している。ただ、それに見合った結果を出す厳しさはあるけれど。
SIerからWEB系の転職を考えている人は、WEB系企業はバラ色だと思い込まない方がいい。WEB系企業も人材が増え、SIerのような組織化は避けられない。今年は、スピードとそれにマッチした組織を創れる人(これが真のマネージャだろう)が必要とされる時代だ。WEB系企業への挑戦は、SIerで自分のゴールを達成してからでも遅くはない。逆に、SIerで厳しいゴールを達成した人と一緒に働きたいなぁ、と思う今日この頃である。
2012年7月1日日曜日
退職、みなさまに感謝!
昨日、某システム受託開発会社を退職しました。
退職にあたり、みなさまから気持ちよく送り出していただきました。
送別会も2回していただきました。
やはり、前回大赤字だったプロジェクトを今回は黒字にできたという貴重な経験をしたことは自分にとって非常に貴重な経験でした。昨日、部署全員の前で退職の挨拶、送別会に参加する中、このプロジェクトは様々な方のご支援、ご協力があってこそ、目標を達成できたのだと実感しました。
また、プロジェクトの雰囲気も少しずつ「やればできるんじゃないか」というポジティブな状況になってきていると思います。一度黒字化しても、継続して利益を上げるという次に繋がる仕組みを構築できないと仕事をする上で意味がないと思っています。
お客さまも、見積もり、上流工程を順序立てたプロセスで進めることで、受入試験の手間が減ることを実感していただけたのではないかと思います。ただ、まだお客さまの要望に100%応えられる組織になっているか、といえば、契約、開発プロセスだけをとってみてもまだまだ改善の余地があります。
転職する理由は、新しいことにスピーディーにチャレンジしたいことと既存のSIerのビジネスモデルに限界を感じていることです。多くのSIerのビジネスモデル、一括請負のビジネスモデル、協力会社の社員を使って利益率を上げるビジネスモデルは、曲がり角に来ているのではないかと考えます。
では、多くのSIerは、なぜ変われないのか。人月商売という慣習を変えられないのではありません。SIerの経営者もそこまでバカではないと思います。SIerの経営者が従業員の年齢構成に頭を抱えているからです。古くから存在するSIを業とする企業は、40代の社員&管理職が多く、20代が少ない。つまり、人員管理、外注マネジメント、社内調整がメインとなってしまい、お客さまの業務課題を解決するという企業にとって本来生産的な業務を遂行することができません。簡単に言えば、現場から遠ざかっているため、リスク管理、進捗管理(ただ、進捗表を見て確認するといったレベルは除く)ができない人が多いのです。実際問題があっても、現場で通用しない解決策を提示されたり、そもそも起こりうる問題すら指摘できないことが多い。
管理職が多いことで、管理職1人あたりの部下の数が少なくなり、予算や利益目標を達成するためには、協力会社の人員を多くして稼ぐしか会社として成長できなくなります。実際、コアな部分を協力会社のあるメンバーに依存しているプロジェクトは少なくありません。保守契約でお客さまからお金をいただけなくなり、そのメンバーをリリースせざるを得ず、引き継いだ社員が大変な思いしています。システム開発において丸投げをせずに外注管理をするならば、非常に高いマネジメントスキル、技術スキルが要求されます。しかし、そのようなスキルを持った社員はほとんどいません。
SIerのやり方が悪いというより、従業員の高齢化、管理職の割合が多くなっていることが問題の根源です。40代以上の社員の意識、行動を変えることは非常に大変です。実際、日本で元気なIT企業の平均年齢は30代前半以下です。計画から実行へ移すスピードが違う。自分もこのスピード感のある企業で働いてみたいと思ったのが、転職する理由の1つです。
転職するにあたってもう一つ重視したのは、組織として成長できる仕組みを経営者が意識しているかどうか。自組織の価値を説明できるかどうか。目先の利益額を増やすために安易に外注していないかどうか。後輩、後継者を育成する仕組みを経営者が意識しているかどうか。
今までの経験を活かして、来月から組織が継続的に成長する仕組み、後輩、後継者を育成する仕組みを創り上げていきたいと考えています。
改めて、様々な貴重な経験をさせていただいた前職関係者のみなさま、お世話になりました。
これからもよろしくお願いいたします。