2014年12月24日水曜日

2014年を振り返って

2014年を振り返ってみると、歴史は繰り返されるというか、予想どおりそうなったなぁと思った。

個人的なキーワードは、「システム連携」「好景気」である。

まず、システム連携について。

クラウドが普及したとはいえ、「システム連携」のノウハウは必要だし、そこにかかるコストは以前と変わらない。10年くらい前のEA・SOAブームのときも同様だ。基幹システムをはじめとした既存システムとの連携ノウハウは、関係部署との進め方含めて一朝一夕で身につくものではない。多くの日本の大企業にとって、ただSaaS含むパッケージソフトを提供したところで、彼らの課題は解決しない。結局、既存システムおよび新規パッケージ双方を熟知したSEが必要となる。こういう連携案件ができるSEは、2014年現在いくらでも仕事あります。単価は高くはないですが、仕事に困ることはありません。そういう意味では、10年前と仕事内容は、全く変わってないんですよね。(単価は下がってますが...)
GUIで連携を設定するEAIツールとかありますが、SaaSとか使っていると、パフォーマンスの制約があったりするので、結局はコーディングした方が、維持管理コストが少なくて済む場合が多い。そういう意味では、AWSはニーズを捉えていると思います。個人的には、システム連携する 担当者は、プログラムを組めるスキルのある人でないと無理だと考えてます。

一方、中小企業は予算がないので、ベンダーからすれば、パッケージを大量に売って利益を稼ぐしかない。まぁ、そもそもシステム連携の必要性がない場合が多いので、それはそれでよいかと思う。


次に好景気について。

リーマンショック前も、SE不足だった。多くの大手企業で大規模(大人数)な案件の開発が進み、デスマーチもたくさんあった。
2014年もその傾向が始まったと感じている。この一年で株価も上がってますし、みずほ銀行、マイナンバーなどの大規模案件の影響で受託開発するSEの人手不足が出ている。
2015年は、このような大規模案件で人がとられる影響もあり、クラウド連携するSE不足もより顕著になると思う。そうなると、程度の差はあれ、連携して出来上がったシステムの品質問題が出始めるのではないか。単にシステム連携が問題なのに、
クラウドはダメだといった論評が出てしまうのではないかと懸念している。
極論かもしれないが、そうならないことを願っています。



2014年10月8日水曜日

曖昧性との...

最近は、技術的なことにあまり時間をとっておらず、プロジェクトマネジメントに関することに時間を割くことが多い。
プロジェクトマネジメントといっても、最近ブームになっているスクラム・アジャイル・リーンいったものではなく、昔からある開発手法(ウォーターフォール)だ。

現在、ITエンジニアは人手不足で、10年前と比較するとシステム受託開発の単価も下がっている。パッケージ導入担当者(コンサルタントという肩書きの人もいる)含めて少人数で効率的にITシステムを構築する必要が出てくる。
パッケージ導入含む受託開発の場合、原価を押さえるための一番の要因は、プロジェクトマネジメントだ。お客様をスムーズにディレクションし、必要最小限のメンバーと開発を進める。少数精鋭でプロダクトを組み合わせたアーキテクチャを提案し、一人あたりの単価を上げるという方法でしか生き残る道はない。

曖昧性とのたたかい―体験的プロジェクトマネジメント論 

曖昧性との共存


この2つの書籍は読んでいて「そうそう。そうだよなぁ。」と納得することが多い。
また、実際に開発に携わっているとき、「ここ注意しないとなぁ」とチェックリストとしても使える。
この本は、あと20年経っても色褪せないだろうなぁ。

2013年12月31日火曜日

2013年を振り返って

今日で、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

クラス構成とか考えてません。main関数にベタ書きです。

ソースの説明です。
まず、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でハマったところ

playframework1系は、リクエスト・ジョブ単位でトランザクションを管理している。 シングルトランザクションで業務処理を行う場合は、分かりやすいのだが、マルチトランザクションを用いないと実現できない場合は、かなり面倒なことになる。 
個人的には、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もいくつか追記しないといけない。


  1. db.pool.maxIdleTimeExcessConnectionsを記述しないとDBのコネクションが解放されずに増え続け、一定時間後にPersistanceExceptionが発生する。
  2. 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でこれらのデータを参照、更新しています。これからの時代のサーバ構成、ミドルウェアの選択に関して考えさせられる発表でした。

 

一日目の感想は以上です。

二日目の感想は、また今度...