Hatena::ブログ(Diary)

達人プログラマーを目指して このページをアンテナに追加 RSSフィード Twitter

2014-05-19

JJUG CCC 2014 Springに参加してきました

本日、日本Javaユーザーグループ(JJUG)主催のCCC 2014 SpringというJava勉強会に行ってきました。会場は、ベルサール西新宿で、都営大江戸線都庁前のA5出口を出て、新宿中央公園の5分くらい歩いたところにありました。今はスマートフォンで地図を確認しながら行けるので、初めての場所でも方向音痴の私でも電車の駅さえ間違わなければ大丈夫ですね。

CCCというのはCross Community Conferenceの略で、さまざまなコミュニティーの交流の場となる会議という趣旨でしょうか?このCCCというイベントは2012から開催されているようなのですが( CCC | 日本Javaユーザーグループ)、今回初めて参加させていただきました。残念ながら個人的な都合から、基調講演と午後の前半のセッションのみで後半と懇親会には参加できませんでしたが、参加したセッションについてまとめます。その他のセッションについては、以下に情報があります。

K-1 詳説 Java SE 8 – CCC Edition(櫻庭 祐一氏)

最初のセッションは、最先端Java技術を研究し、最近Java8紹介記事も多く執筆されている櫻庭さん(@skrb)より、Java SE8の新機能のポイントについて紹介していただきました。Java SE8というと、まず、Lambdaプロジェクトの成果であるラムダ式ストリームAPIを使った新しい関数型のJavaプログラミングが注目されますが、それ以外にも、

など、その他の新機能についても解説されました。途中、

「for文やforEachを使ったら負け。ラムダ式禁止と戦おう」

というコメントが印象的でした。現状は後の岩崎氏の講演で説明があったように、アプリケーションサーバーなどの対応が進んでいないという制約から、Java8が実際の案件で普及するまでにはにはもうしばらく時間がかかるだろうとは思いますが、今のうちに新しい機能について先行して学習しておき、実際使えるチャンスがあったら、便利な新機能を積極的に導入できるよう準備しておきたいですね。

なお、この基調講演の元ネタは、「現在、ITpro において連載している詳説 Java SE 8 を CCC で再現します。」とのことですので、

詳解 Java SE 8 第1回 Java SE 8概説

からはじまる、素晴らしい詳細な連載記事も是非ご覧ください。

K-2 Java 8 ラムダ式と Stream の概要について(Stuart Marks氏)

基調講演の2番目は、オラクルのStuart Marks氏より、ラムダ式ストリームAPIについて、基本的なところから解説していただきました。いきなり、新しい関数型の記述方法で説明されると、慣れていない場合混乱する場合もあると思いますが、以前の書き方と対応させながら丁寧に解説していただき、理解しやすかったです。

今回の講義で特に印象的だったのは、関数型や不変性という話を前提にせず、あくまでも従来からある無名内部クラスの代替として型安全にコードブロックを渡すための便利な記法、内部イテレーターの記述手段としてラムダ式を説明していたことです。例として

List<Person> list = ... ;

// Java7 
for (Iterator<Person> iter = list.iterator(); iter.hasNext();) {
    Person p = iter.next();
    if("Jones".equals(p.getName())) {
        iter.remove();
    }
}

// Java8
list.removeIf(p -> "Jones".equals(p.getName()));

のように、Collectionインターフェースに追加されている、removeIfを使って、従来のイテレーターの処理を置き換えるコードが出てきました。さらに、従来の外部イテレータとfor文を使って処理した場合と比較して、同期化が必要なコレクションの場合に、きちんと同期化をしてくれるというようなところも便利ですね。*2

先の櫻庭さんの発言にもありますし、今まで私自身ラムダ式を使う以上、なるべく関数型の発想で考えるべきであり、可変な(mutable)な操作は避けるべきと考えていました。しかしながら、もともと、Javaは可変な変数を当たり前に使う手続き型(imperative)なコードを前提としており、不変性などは後から追加されたというところがありますし、このようにラムダ式は可変な操作にも使えるのだというのはかえって新鮮な発見でした。特に、古いコードをラムダ式を使って簡潔にリファクタリングするという場合などには、あえて不変性にこだわらないというのも一つの考え方かもしれません。

Stuart氏の話で、もう一つ印象的だったのは大量の基本型の数値を使った計算に、ストリームAPIを適用するという以下の例*3です。

System.out.println(
    LongStream.range(0, 1_000_000L)
        .parallel()
        .map(i -> ((i & 1) == 0 ? 1 : -1 * (2 * i + 1))
        .mapToDouble(i -> 4.0 / i)
        .sum());

従来の常識としては、大量の数値をList<Long>などのコレクションを使って計算すると、基本型からオブジェクへの変換(boxing)が行われて性能で問題が出るので、代わりにlong[]のように基本型の配列を使わなくてはならないということがありました。しかし、これはコレクションなど便利なAPIが使えずC言語のようなコードを書かないといけないということを意味し、パラレル化などの最適化には相当の努力が必要でした。ストリームAPIでは、LongStreamやmapToDoubleといった基本型専用のAPIをきちんと使いさえすれば、遅延評価がきちんと行われ、実際に大量の値のboxingが発生せず、オーバーヘッドを最小限に抑えることが可能なようです。確かに、Javaでは基本型の扱いはユーザーにとって完全に透過というわけにはいかず注意が必要なのですが、こうした数値計算にも関数型を活用できるというのは面白いですね。

R1-1 Java 8 for Java EE 7/6(岩崎 浩文氏)

金融、製造、公共など様々なドメインJavaEEを使った多くのシステム開発を担当してこられ、雑誌等への執筆もされている楽天の岩崎氏(@HirofumiIwasaki)より、アプリケーションサーバーのJava8対応の状況についてお話いただきました。

JavaSE 8が正式にリリースされたということで、早速現在のプロジェクトで活用しようという気になってしまいますが、実際のところは、JavaEE 7ではJavaSE 8はサポート対象外であり、さらに、そもそもJavaEE 7に対応したアプリケーションサーバーGlassfishWildFlyといったオープンソースサーバーに限られ、その他の商用のサーバーではいまだにJavaEE6しかサポートされていないという事実があります。ただし、講義中で紹介されていたようにGlassfishのdaily build版ではJava8が使えるということですし、WildFlyなど他のサーバーについても比較的早く対応されるのではないかという期待がありますね。

また、パラレルコレクションなどは通常のEJBのようなオンライントランザクション系のシステムとは相性が悪いと思います。しかし、EJBJavaEEのすべてではないですし、JavaSE 8が利用できるようになれば、日付APIやラムダを使ったロジックの簡潔化など、いろいろなメリットがあるものと期待されます。

なお、日本語の情報が少ないという問題はありますが、JavaEEについては以下のNetBeansチュートリアルにあるサンプルに取り組むのがよいとのことです。

https://netbeans.org/kb/trails/java-ee.html

H-2 Javaトラブルに備えよう(上妻 宜人氏)

上妻氏は見習いプログラミング日記Java EEを中心とした情報の発信をされていますが、単にプログラミングを中心とした開発手法のみならず、運用時に必要なモニタリングツールの知識など有用な情報を書かれています。どうしても、新しいAPIや言語の機能、開発ツールなどに興味がいきがちですが、実際には運用時のトラブルシューティングをするためのログ解析手法などは非常に大切です。また、必要なツールを正しく使いこなせば、トラブルシューティングが容易であるというのもJavaの重要な特徴の一つなのではないかと思います。つまり、Javaは単にプログラミング言語というだけではく、デプロイメント・運用時の環境まで含めたプラットフォームなのであるということですね。

講義の中では、トラブルシューティングのために適切な情報の取得が大切であるとして、まず、以下の情報出力の方法について説明されました。

さらに、OutOfMemoryErrorが発生するさまざまなケースを突出型、じわじわ型などパターンごとに解析する手法について解説されました。基本的な手法は昔から大きく変わっていないとはいえ、具体的なコマンドの使い方はバージョンによって異なっているため、上妻氏の最近の経験に基づいた情報は非常に有用なものであると思います。いざ、トラブルが発生すると焦ってしまい、冷静な判断ができないということもあると思いますので、Javaエンジニアとしては日頃からこうした解析の手法に慣れておくことは大切だと思いました。*4

H-3 初めての Java EE 開発から学んだこと(菊田 洋一氏)

株式会社 構造計画研究所の菊田氏(@kikutaro_)より、ご自身が初めてJava EEの開発に取り組まれたプロジェクトの経験をもとにお話されました。菊田氏は以下のブログでもJava EEの情報を発信しておられます。Challenge Java EE !

恥ずかしながら、講演の中で私のブログもちょっと紹介していただいたのですが、3年近く前(もうそんなに経つんですね)にちょっとJavaEE 6について調べてこのブログでも紹介したことがあった(Java EE6標準の範囲でフルスタックのWebアプリケーションが簡単に作成できることを確かめてみました。 - 達人プログラマーを目指して)ので、昔のことを思い出してちょっと懐かしくなりました。

残念ながら、私自身はその後JavaEEから離れてしまい、新しいEEのフレームワークを実際の案件で使うことはできなかったのですが、菊田氏の発表はJavaEEを実際に適用した成果に基づくものとして、大変興味深く聴かせていただきました。

発表にもあるように、もともと.NET系の開発からJavaEEに移行されて、まだほんの一年半という短い期間にも関わらず、データ層からプレゼン層まで「フルスタック」のアーキテクチャを構築されたということは大変感銘を受けました。これはもちろん菊田氏の努力の賜物だと思いますが、JavaEEが標準のフレームワークを組み合わせるだけで実用的に使える、.NET並みに簡単に使えるようになったということの証明となる事例なのではないかと思います。

  • 標準以外のフレームワークやツールがたくさんあって選択にまようけど、いろいろ悩むのは楽しい
  • 日本語の書籍が少ない
  • Javaコミュニティーが盛んで初心者にも間口が広い

といったことは、私も以前から感じていたことで、多くの点で大変共感しました。菊田さんご本人の以下のエントリーもどうぞ

#JJUG_CCC Spring 2014で「初めての Java EE 開発から学んだこと」というタイトルで発表させて頂きました! - Challenge Java EE !

*1:時間の関係で残念ながらほとんどスキップされましたが、櫻庭さんはJavaFXを推進されており、日頃プレゼン資料自体もJavaFXで作成しているとのことです。http://www.slideshare.net/skrb/20140321-javafx8も参考になります。

*2:Coolectionsのようなユーティリティクラスと違い、インターフェースに定義されたデフォルトメソッドはオーバーライド可能なので、サブクラスごとに独自の実装が持てる。

*3円周率を計算するテイラー級数の計算

*4:DevOpsという考え方があるように、最近はプログラマーも開発だけでなく、サーバーの運用やトラブルシュートをすることが多いと思われます。

2014-05-10

開発チームにアーキテクトがいないなと感じてしまうような、残念なコードスメルの例

まったく個人的なモチベーションの問題から、前回の最終更新から2年以上が経過してしまい、多くの読者のみなさんにはご心配をおかけいたしました。「プログラミングに関して調べたことや日々感じたことをメモとして残していきたいと思います。」というもともとの原点に立ち返って、あまり気負わずに、また今後も時々更新していけたらと思います。今までこのブログの主なテーマとして、JavaEEやSpringといったような、いわゆる業務開発で使われるような技術を中心としてきたわけですが、最近Springを使ったJavaの開発に(アーキテクトではなく)プログラマーとしてちょっと参加する機会があったので、その時気づいたこと、感じたことを書いてみたいと思います。

さて、皆さんはアーキテクチャやアーキテクトという言葉に対してはどのようなものをイメージするでしょうか。システムのセキュリティを確保するための方式であったり、大量のデータを短時間に処理する並列化の仕組みであったり、また、効率的な業務フローの構築だったり、ソフトウェアアーキテクチャという言葉はコンテキストによって実に様々な対象を意味します。実際には、ソフトウェアアーキテクトといってもさまざまな仕事があり、また、それぞれの分野において膨大な知識が必要なため、最近ではお医者さんのように専門の得意分野に特化せざるを得ないということもあるかもしれません。基本的には、アーキテクトはプロジェクトの成功を左右するような基本的な設計方針、技術の選択といったことに関わってきます。

ここでは特に、クラスやパッケージ、設定ファイルの分割といった開発作業に深くかかわってくる、プログラミングの基本指針のことを単にアーキテクチャと呼ぶことにします。自分の経験からも、このプログラミングに関わるアーキテクチャプログラマーの開発生産性や、後々のコードの再利用性、保守性といった点に深くかかわってくる開発の最重要ポイントの一つであり、他のアーキテクチャ指針とともにプロジェクト成功のためには軽視できないものであると考えています。この意味において有効なアーキテクチャを構築するにあたっては、アーキテクトがアプリケーション開発チームのメンバーとして仕事をするか、少なくとも、深く関与するということが大切だと思います。アーキテクト自身もアプリケーション開発者のコードを少なくともレビューできる体制になっているべきだし、「現場のプログラマーの気持ちがわかる」状態が望ましいと思います。さらに、こういったプログラミングアーキテクチャは事前にあらかじめ決められるものではなく、繰り返しのリファクタリングを通して、繰り返し洗練していくというアジャイルプロセスが必須であると思います。以前から私が「下流アーキテクト」という言葉を何回か使ってきましたが、少なくとも有効なプログラミングモデルを構築するにあたって、アーキテクトは重役椅子に座ってパワーポイントの資料を編集しているだけではなくて、実際に開発チームを率いるプログラマーでもあるべきなのです。(アーキテクトもプログラミングするべきか? - 達人プログラマーを目指して

残念ながら、多くのプロジェクトにおいては、開発チームの中にこうしたアーキテクトがいないのでないかと感じることがあります。実際に、そういった事実は実際にソースコードを読んでいるといくつかの特徴から明らかになります。ここでは、アーキテクト不在を感じるソースコードの不吉な臭い(スメル)の例について、いくつか書いてみたいと思います。

間違った過剰なコンポーネント(プロジェクト)分割

初心者のソフトウェアアーキテクトでも、最初に考えるであろうことは、何とかして全体のコードを分割しなくてはならないということでしょう。モノリシック(一枚岩)なアーキテクチャがダメという考えがあるためか、とにかく、コードをいくつのコンポーネントに分割したくなります。全体のソースコードが多くのコンポーネントに分割されていれば、それだけでいい仕事をした気分になってしまうというところもあるかもしれません。*1

しかしながら、コンポーネントの分割には一定のコストが伴うということを忘れていはいけません。単にチェックアウトしてIDEの中で扱わなくてはいけないプロジェクトが多ければそれだけ面倒が増えますし、全体的なビルド時間も分割が増えるにしたがって急速に長くなる傾向があるため、CIの効率的な実行に支障が出ます。XP的な要件を満たすもっともシンプルな設計を目指すのであれば、どうして分割が必要なのかというメリットを考慮したうえで、分割は必要最低限にするべきだと思います。適切なコンポーネントの分割は簡単そうでいて、実は非常に難しいところがあると思いますし、実際、要件に合った最適な分割は何回かのイテレーションを経てようやく到達できるということも珍しくありません。一方、チームにアーキテクトが不在だと、以下のような形式的な分割の基準をあらかじめルールとして設定してしまい、結果として開発生産性を大きく下げるということになりがちです。

こうした形式的な基準に従って分割した場合、一つの開発チームに割り当てられたプロジェクトの数が何百個になることさえあります。実際問題として、プロジェクトの数以上に問題なのは、こうした形式的な分割方法によって得られるのは多くの場合、密結合で凝集性の低いアーキテクチャであるということです。要するに、一見きれいにコンポーネントが分割されているようにみえるが、実際は関連した機能があちこちに分散し、実質はモノリシックなシステムと変わらない、結局は何も分割したことになってはいないという状態です。例として、Springのbean定義をxmlで記述しているとして*3xmlのbean定義ファイルと実際のbeanの実装クラスを別々のプロジェクトに分割して管理するというルールを考えてみてください。当然beanの定義と実際のクラスは密接に依存し合っているので、通常は同時に更新する必要がありますし、別々のプロジェクトとしてビルドすることで常に不整合が発生することを避けられません。プログラマーの気持ちがわかっているアーキテクトであれば、最初からこんなルールにはしないし、むしろアノテーションを使ったりJavaソースを使ってbeanの設定とクラス定義を近くに配置するということを考えると思いますが、そうでないと、設定ファイルは別々のプロジェクトで管理するものという常識で考えてしまいます。

私としてはeclipseプロジェクトのようなビルドの単位となるコンポーネントの分割は最低限にすることをお勧めします。もちろん、分割するメリットとして、

といったようなことがありますが、比較的小規模なプロジェクトであれば、

くらいの分割からスタートするので十分なのではないかと思いますし、むしろ最初から過剰に分割された構造で進めるより、実際上ははるかに生産性が高いと思います。

フレームワークによって強制されたパラレル継承

これは、ずっと以前に侵略的なフレームワーク - 達人プログラマーを目指してで書いたことの繰り返しになりますが、フレームワークの規約によって一つの機能ごとに様々なクラスや設定を作成しなくてはならないルールになっている場合がよくあります。たとえば、

  • MusicTrackDao
  • MusicTrackModel
  • MusicTrackService
  • MusicTrackView
  • MusicTrackViewModel
  • musicTrack.jsp
  • JSPの<musicTrack>タグ
  • 個々のbean定義
  • 個々の単体テストクラス

といったように、同じ名前で始まる大量のソースが存在していれば、パラレル継承のスメルを発しているといって間違いありません。*5

なお、関連してこのようなケースでは、レイヤーごとに値の入れ物として別々のクラスを定義することが強制されている場合も多いのですが、実際に多くの場合

musicTrackViewModel.setTitle(musicTrackModel.getTitle());
musicTrackViewModel.setTrackData(musicTrackModel.getTrackData());
...

のように、記述するコードの大半が単なる値の転記となることもあります。

これも、実際にプロジェクトにアーキテクトが参加していれば、そんなナンセンスな設計ルールにはしないはずなのですが、事前にアプリケーション開発チームとは別の標準フレームワークチームがルールを決めた場合など、このアンチパターンによく出会います。コンポーネント分割の場合と同様にたくさんのクラスを作成させることで、メンテナンス可能なアーキテクチャを作っているんだという気分になるという人もいるかもしれませんが、実際のところは、これも密結合・低凝集なアーキテクチャの原因となり、生産性を大きく低下させる元となります。大量の無駄なクラスを作成しなくてはならないために、初期の開発に時間がかかるという点に加えて、さらなる問題は「変更の分散」といったコードスメルの原因となることにありますね。つまり、後々のメンテナンスであちこちのファイルを同時に編集しなくてはならないということです。

もちろん、本当に継承が適切ならば継承を使えばよいのですが、JUnitやSpringMVCの昔のバージョンと今の最新バージョンを比較してみるとわかるように、最近のフレームワークでは共通のベースクラスを避ける傾向があると思います。*6

共通コードのプルアップがされていない

何らかのMVCフレームワークアプリケーションを作っているとして、以下のようなコードがあったとします。いったい、何が問題なのでしょうか。


/**
 * 共通ベースコントローラー
 */
public abstract class AbstractController {
    protected abstract void execute(RequestContext context);
...
}

/**
 * 返品ポリシーのリンクを描画するためのコントローラー
 */
public class ReturnPolicyController extends AbstractController {

    public static final String RETURN_POLICY_MODEL_ID;

    @Inject
    private ModelRegistory modelRegistry;

    protected void execute(RequestContext context) {
        ReturnPolcyViewModel viewModel = modelRegistory.findModel(ReturnPolcyViewModel.class,  RETURN_POLICY_MODEL_ID);
        if (viewModel == null) {
           throw new InvalidConfigrationException("No model found for " + RETURN_POLICY_MODEL_ID);
        }
 
        viewModel.setURL(URLConverter.convertURL(context, model.getURL()));
        .....           
 
        context.setViewModel(viewModel); 
    }
}

/**
 * 音楽のトラック情報を描画するためのコントローラー
 */
public class MusicTracksController extends AbstractController {

    public static final String MUSIC_TRACKS_MODEL_ID;

    @Inject
    private ModelRegistory modelRegistry;

    @Inject
    private MusicTracksDataSource musicTracksDataSource;

    protected void execute(RequestContext context) {
        MusicTracksViewModel viewModel = modelRegistory.findModel(MusicTrakcsViewModel.class,  MUSIC_TRACKS_MODEL_ID);
        if (viewModel == null) {
           throw new InvalidConfigrationException("No model found for " + MUSIC_TRACKS_MODEL_ID);
        }
 
        .....           

        context.setViewModel(viewModel); 
    }
}

...似たようなサブクラスが何百と存在

普通の感覚であれば、各サブクラスのコードの類似性に気づくと思います。共通のロジックを親クラスに移動(プルアップ)するなどして、重複を減らすべきでしょう。しかし、ここではイメージなので実際のロジックを省略していますが、実際に各画面ごとのロジックが記述されている場合、この類似性に気づかずに大量の似たようなクラスを作成してしまうことがあります。こうしたコードの類似性は実際にいくつかのサブクラスを作成してみないと気づかないことが多く、フレームワークチームから与えられたベースクラスは多くの場合重複コードの削減のためにあまり役立ちません。アーキテクトが開発にかかわっているのであれば、こうした重複を発見する都度リファクタリングによって取り除く努力をすべきだと思います。

手続き型のコード

これはこのブログでも何度か取り上げてきたことですが、Javaなどのオブジェクト指向の言語を使っているにも関わらず、ほとんど活用できていないというケースが結構あると思います。実際、そういったプロジェクトで作成されたコードをみると、

  • データとgetter、setterだけのクラス
  • すべてstaticメソッドからなるXXXUtilクラス*7、あるいは巨大なサービスクラス
  • ポリモーフィズム多態性)が使えておらず、Enumや型によって似たようなswitch文の構造が繰り返し現れる

といったような手続き型の言語で設計したのと大差のない構造になってしまっています。これは、要件やチームのスキルによっては必ずしもアンチパターンとまでは言えないかもしれませんが、やはり、プログラミング言語のあるべき設計を使いこなせるアーキテクトがチームに存在していないのが原因の一つなのではないかと思います。

ところどころに散在する実験コードの痕跡

コードのアーキテクチャのスメルは、なにもスキルの低いプログラマーのみで構成されたチームで起こるとは限りません。非常にモチベーションがあって、やる気のあるプログラマーであれば、自然なこととして、いろいろと自分の新しいアイデアをどんどん試したくなります。それは、技術者としてはすばらしいことなのですが、業務アプリケーション開発のプロジェクトの顧客の要件を最短で満たすという制約された条件の中では、ある程度節度をもって計画的にやらないと問題となることがあります。実際、うまくいかなかったアイデアなどは未練を捨てて早期にクリーンアップするべきだと思いますが、実際上は時間の制約からか、あるいはプログラマーが入れ替わったからか、ところどころに過去の遺産がデッドコードとして残されることがあります。そういったデッドコードが存在していると、障害の解析が困難になったり、後々機能追加が大変になったりメンテナンスの上で苦労することになります。

そういった問題を防ぐためには、やはりアーキテクト的な視点からコードの状態を監視し、常に余分な複雑性が取り残されないようにする努力やプロセスが必要だと思います。

最後に、最近気づいたことを

最後に、最近になって気づいた自分の間違えについて書いておかなくてはなりませんね。以前であればこうした設計上の問題は日本のSI業界の構造が問題なのであるという話をしていたかもしれません(^_^;)が、ここで書いたような話は多少フィクションが入っているとはいえ、実際私がSI業界以外の今の会社で体験したことに基づいていると告白しなくてはなりません。言語の特性から、Javaで開発していると、こういった設計上の問題が起きやすいということがある可能性もありますが、こういった話はSIer以外でも、どこの国の開発チームでもあるのだなということですね。

こうした設計に陥る原因として考えられるのは、SI業界の構造というより、むしろ、アーキテクトがアプリケーション開発チームと一緒に仕事していないという問題にあるのではないかと思います。そして、実際多くの場合、「フレームワークチーム」「共通チーム」というのがアプリケーション開発チームとは切り離されて存在しており、フレームワークを開発プロジェクトが開始する前に作成して提供するというようなモデルの場合に起こりがちなのではと思います。さらに、非常によくあるパターンとして、あるバージョンのフレームワークを使ってアプリケーションの開発が進められている時点では、フレームワークは既にアクティブに開発されておらず、フレームワークの改善に興味がないということがあります。既にフレームワークチームは「次世代フレームワーク」の開発に目が移っていて、古いフレームワークはよほどのバグがない限り手を付けないというようなケースが多いかもしれません。

自分としては、なるべくオープンソースフレームワークを活用するなどして、自社フレームワークの部分を最小限にし、アーキテクトはアプリケーションアーキテクチャの改善にもっと目を向けるべきなのではないかと思うのですが、さまざまな政治的、ビジネス的理由からそれができないのが問題でないかと思いますね。

*1:なお、ここではコンポーネントとはJavaパッケージのような論理的な名前空間の分割ではなくて、eclipsemavenのプロジェクトに相当するようなビルドデプロイの分割単位のことを指すものとします。

*2:場合によってはインテーフェースやアノテーションを分けるのが有効な場合ももちろんありますが、それにはちゃんとした理由があります。リモートのサービスでインターフェースだけをクライアントから使うとか、昔のSpringがそうしていたように、JDK1.4をサポートするために、アノテーション依存の部分を分けるといったような例があります

*3レガシーコードだったらともかくも、新しいプロジェクトでxmlに個々のbean定義を書くような規約だったら、これ自体かなり疑問な設計方針なのですが

*4コンポーネント分割の構造とチームの構造がマッチしているのは基本的によいことだと考えられます。

*5:そして、多くの場合作成すべき各コードにベースとなる親クラスやインターフェースが存在してそれを継承して作成するルールになっているのですが、実際親はマーカーというか、実際になんら本質的な役割を持っていないという場合も多いです。これは親クラスが実際の必要性から作られたのではなく、最初からルールとして存在しているという何よりの証拠といえます。

*6:いわゆるPlain Old Java Object=POJOとして作成可能、継承などはアプリケーション側の裁量で自由に使えるようにする。

*7:StringUtilsやCollectionsのような標準のライブラリーにもみられるように、どこのクラスにも属さないロジックの格納場所として、最低限のUtilクラスは特に問題ではないと思います。ここで問題としているのは、大部分のビジネスロジックがUtilクラスで書かれているというようなケースですね。

2012-04-22

アマゾンにおけるソフトウェア開発の仕事について感じたこと

ちょうど、先日アマゾンオープンハウスというイベントでお話をさせていただく機会があったのですが、開発者向けの20日のセクションだけで90名近くの方々にご参加いただきました。平日にもかかわらず、多数の方々にご参加いただき、どうもありがとうございました。

私自身は、昨年秋にSIerからアマゾン転職してまだ半年ですが、この機会にアマゾンにおけるソフトウェア開発の文化や考え方について、ブログでご紹介できる範囲でまとめてみたいと思います。

私は、ずっとブログに書いてきたようにSI業界からの転職だったのですが、一般的なSIerにおけるソフトウェア開発の考え方や手法といろいろな面で違っているということは予想していたというか、もともと覚悟の上での転職でした。それでもやはり最初のうちはあまりにも大きな変化に自分の仕事のスタイルを合わせるのにいろいろと苦労しました。基本的には転職したての頃に抱いた感想(転職して感じたウォーターフォール文化とアジャイル文化の違いについて - 達人プログラマーを目指して)から大きくは変わっていないのですが、徐々に会社の文化や仕事のスタイルに慣れ、また、開発環境やツールにも習熟してくるにつれて、始めの頃の不安や戸惑いがようやく薄れて、徐々に自信や面白みに変化してきたかなという段階です。

SDEはやはりプログラミングが仕事の中心

アマゾンでもアプリケーション開発からインフラ、コンサルティングまで様々なエンジニアのポジションがあるのですが、私はソフトウェア開発技術者(Software Development Engineer、SDE)という役割で、携帯電話用のWebサイトを開発するAnywhereというチームで働いています。*1SDEとはいわゆるプログラマーのことなので、SIerで働いていた頃と違って、実際にアプリケーションのコードを自分で作成・修正するということが仕事の中心となります。

もちろん、開発環境が動かなくなってトラブルシュートに時間を取られたり、他のチームとのコミュニケーションに必要な時間もあるため、毎日すべての時間をコーディング作業に費やすということが可能なわけではありませんが、できる限りコーディングに時間をさけるようにすることが生産性の高いSDEとしては義務であり権利でもあると考えられています。前職では何か月もExcelの設計書を書いたり、パワーポイントの提案資料を考えたりという時期があり、コードを書くことも他の開発者向けのサンプル程度というプロジェクトが多くあり、プログラマーとしては欲求不満になってしまう場合が多くありました。現職では、とにかく実際にアプリケーションの機能を自分自身で実装するという仕事に堂々と集中することができ、プログラミング技術を発揮し、さらに腕を磨きたいと考えていた私にとっては大変に適合した仕事でうれしく思っています。

そういうわけもあって、SDEの採用面接では、まず何よりもプログラミングや開発の基礎力が問われます。プログラミング言語を使ったロジックの記述から、データ構造やアルゴリズムといったコンピューターサイエンスの基礎知識が問われるようです。個人的には実際の開発に必要な経験や知識はそれ以外に、開発ツール、フレームワークミドルウェアを使いこなすことが重要だとは思いますが、多くの場合は面接で能力を測る基準としては基礎力を重視しているようですね。

プロジェクトの規模とペース

それから、SIerの場合と大きく異なることとして、一般に個々のチームやプロジェクトの規模が小さく*2、とにかく数週間から数か月といった早いペースで機能を連続的にリリースしていくということがあります。オープンハウスでも紹介したように、アマゾンでは、Scrumというアジャイルプロセスが標準的に多くのチームで採用されています。通常は提案や画面設計に何か月も費やすということはありませんし、プロジェクトがキックオフしたその日のうちからプロトタイプの着手に取り掛かるということが普通です。そして、数週間から数か月といった単位で様々なプロジェクトが並行して活動し、次々と機能追加をリリースしていきます。

もちろん、アマゾンでもキンドルやプライムといったビジネスモデルに大きく影響を与えるようなプロジェクトだと世界中のたくさんの開発者が参加する大規模なプロジェクトになるわけですが、個々のチームは比較的小規模なチームに分かれていますので、一つのチームの単位としては1人からせいぜい5人程度の小規模なグループで作業します。

文書化の作業はどうしても優先度が大変に低いと考えられているので、最初のうちは呼び出すAPIがわからないとか、そもそも準備されていないといったことや、リリース直前のUATの段階でUIの変更が入ったりということもあります。一般的なSI案件のように決まった設計書を念入りに準備して、その通りに作成、納品するという考え方とは当然大きく違っています。私も、Excel方眼紙などに細かく仕様を記述する方法は嫌いなのですが、APIのドキュメントやアーキテクチャ概要のドキュメントなどはもう少ししっかりしたものがあればなあと時々思うことはあります。特に、自分の英語力の問題から、口頭やラフなメールで説明されるより、フォーマルな文書が基準としてあった方が便利なのにと感じることはありますが、変化のペースがとにかく速いので、文書化はどうしても後回しになってしまう傾向があるようです。

SDEに与えられる大きな権限

個々のSDEは単にコードを記述するというだけでなく、仕様変更やリリース時期の調整などを含めてプロダクトマネージャやデザインチームに対して意見を述べることが期待されます。また、リファクタリングやツール、プロセスの改善などを積極的に工夫し、自らプロジェクトとして提案するというような活動は大いに歓迎されます。*3とにかく、手を動かすということが評価されるようですね。

それから、デプロイメントの自動化などのツールは充実しているので、SDEの権限で本番環境を含めて様々な環境にアプリケーションをリリースすることが可能です。緊急の大きな障害が発生したような場合、一般のスケジュールとは別に急きょ試験、リリーススケジュールを立て、本番へのリリースを行うといったことも発生します。もちろん、さらに大きな障害につながる恐れもあるわけで、これは、私もなかなか最初はすごく緊張したのですが、最近はようやく肝が据わってきたかなという感じです。

新規開発よりも、既存システムの改善

私の担当したSIer案件では、アーキテクチャの提案やビジネスプロセスモデリングといった上流工程からプロジェクトが開始するということは結構普通でした。私はアーキテクトという役割から、比較的新しいフレームワークの活用方法を考えたり、全体的なシステムのしくみを考えるといったこともありました。現在の自分の経験と立場ではそこまで大きな視点でシステムを考えるという段階ではないところもありますが、既存のバグを修正したり、リファクタリングを行ったりという作業が日々の作業の中心となっています。SOAのような大きなアーキテクチャは長い時間の間に徐々に完成させられてきたため、基本的には小さな改善をこつこつと積み重ねるというボトムアップのアプローチです。ただし、新しい技術の採用など、時には思いきった大きな変更やブレークスルーも必要だと思います。

学ぶべきツールやフレームワークなどが無数にある

アマゾンの場合は、AWSなどの公開されたツールもたくさんありますが、社内にはそれ以上にたくさんのツールやフレームワーク、活用すべきデータがあります。他のチームのソースコードは社内では基本的に公開されています。残念ながら、多くのツールは外部には非公開なので、ここではあまり詳しく書けませんが、そういう意味で、いろいろと研究のしがいがあります。

具体的にソフトウェアの改善効果が数値化されている

先日のイベントでもA-Bテスト*4という考え方について紹介したのですが、アマゾンではレスポンス時間などシステム的なことはもちろん、アクセス数や売り上げなどビジネスにつながるさまざまなメトリクスを自動計測する仕掛けが提供されています。したがって、追加した機能が効果的かどうかということがグラフとしてすぐにわかってしまう仕組みになっています。自分の作成した機能の効果がどんなものなのかがリリース直後から確かめられるのは、楽しいものがあります。

もちろん、アマゾンの社員が目指すべき最も大切な目標としてCustomer Obsession(顧客第一)というのがあるので、そういった情報はユーザーエクスペリエンスの向上に活用されます。

英語を使ったコミュニケーションの必要性

アマゾンジャパンの公用語は日本語なので、日本語が通じる人には堂々と日本語を使ってもよいのですが、外国人や海外のチームとコミュニケーションする際にはどうしても英語を使わなくてはなりません。Scrumなどの会議もすべて英語で行われています。*5

結局、私の所属するチームでは、ほぼ英語でコミュニケーションする必要があります。自分の英語力では、何とか会議の話について行って、進捗を報告するというくらいはできても、なかなか自由に自分の考え方を伝えることは簡単ではないというところがあります。やはり、この点に関しては私にとって英語圏の人に比べてものすごいハンディがあると感じざるを得ませんが、技術力などでカバーしていくしかないですね。

英語のハンディという点では多くの日本人だけでなく、中国人も同様のようなのですが、最低限メールやチャットなどで会話ができれば何とかコミュニケーションはできます。また、コードレビューもソースコードdiffを使ってオンラインでコミュニケーションするのでまあ何とかなりますね。

ちなみに、ランチタイムは重要な英会話レッスンのチャンスだと思ってできる限り外国人の同僚と一緒に食べに行くようにしているのですが、おかげでハンバーガーや中華など脂っこい食事を食べる機会が大幅に増えました。アマゾン目黒新オフィスでは社員食堂ができたので、今は自分の好きなメニューを選択できるようになりましたが。

まとめ

以上、最近仕事について感じたことをいくつか簡単に書いてみました。いろいろ苦労するところもありますが、自信を持って日々大いに楽しんで仕事ができているかなと思います。そういうこともあって、最近は情報をインプットして処理するという方にどうしても時間が割かれてしまい、ここのところ、ブログの更新頻度が下がっています。どこまで技術的なことを書いてよいかということはありましたが、JavaPerlなどの一般的な言語や公開されているツールの話については、大丈夫なようですし、また余裕が出てきたら時々更新していければと思います。

*1:日本に携帯サイトの開発チームがおかれているのは、やはり世界的にみても日本の携帯電話の技術や使い方がユニークで進んでいるという事実があります。

*2SOAに従ったソフトウェアの構造にならい、開発組織もカート、カタログ、検索、注文プロセス、運用基盤など、システムやユースケース単位ごとに独立した小さな開発チームに分かれており、全体としてチームがいくつあるのかさえ把握が困難。

*3:最初私も勘違いしていましたが、アマゾンも全然理想郷ではないので、いろいろ問題や改善点がたくさんあります。エンジニアにとっては改善点があることはモチベーションにつながるのでよいのですが。

*4:異なるバージョンを一定割合ごとに同時にリリースして、統計的に効果を確かめるテスト手法

*5:時々裏で中国語や日本語が混じりますが。

2012-02-12

日本のユーザー企業は忍者のようなプログラマーをもっと登用して重用すべきでは

あの記事から一年、ひがやすを氏が以下のエントリーで、プログラマーとして、新しいサービスを作ることの難しさについて書かれています。

僕と君とSIerの生きる道 - Yasuo Funk (元ひがやすを)

確かに私自身は、サービスを作る側に回った(まだISIDにいるけど、ベンチャーで働いているようなものです)のですが、身を持って面白いサービスを作る難しさも経験しました。

面白いサービスを作るのはほんとうに難しい。その後、マネタイズにも成功するのはさらに難しい。サービスを作る側に回って成功するのはほんの人握りの人なんです。

もともと一年前におっしゃっていたことは、SIerのビジネスに将来性はないから優秀なプログラマーは自分でサービスを作る側に回らなくてはならないし、単によいコードを作れるだけでなくて、自分からアイデアを考えられるようにならなくてはならないということだったかと思います。一年前この記事を読んだときは、私としてはかなり衝撃を受けました。一人前のプログラマーとして認められるには、もはや単にきれいなコードを書く技術やフレームワークやミドルの知識だけでは不十分なのであり、自分からビジネスを創り上げるアイデアがなくてはならず、単に勉強して技術力を磨くというだけでは不足であるということのように思われたからです。

どうしても、停滞気味なSI業界の中でエンジニアとして働いていると、ビル・ゲイツマーク・ザッカーバーグのように新しい時代を切り開いて成功者となったプログラマーにあこがれることは自然なことですし、プログラマーとして大きな目標を持って頑張るということは悪いことではありません。しかしながら、現実問題として、そういう成功者に誰もが簡単になれるわけではないですよね。

大きな目標を立てることは立派なことだけれども、これは、戦国時代に例えるならば、すべての武士に対して、信長秀吉を目指せといっているのと同じくらいに難しいことのように思われます。しかし、一方で、政治の表舞台には登場しなくても、裏方として活躍した軍師忍者として活躍したような人もたくさんいたと思われます。そういう忍者たちは、表向きの身分こそ低くても、自分の剣術や諜報スキルを磨くことで、大名に信頼されて、戦略上重要なプロジェクトを任されていたのではないでしょうか。

基本的に、信長の野望のようなシミュレーションゲームにおいては、大名のようなトップに立つ人はすべての能力において優秀でなくては務まらないと思いますが、忍者軍師のタイプは智謀や武力など一部の能力に特化したスペシャリストとして登場します。私としては、多くのプログラマーは大名タイプよりも、むしろこうした忍者タイプを目指した方がよいのではないかと思うのですよね。

忍者スペシャリストですが、大名のそばにいて、重要なプロジェクトを引き受けます。*1これは、現状のSI業界における開発が大部分百姓から臨時でかき集めたような傭兵による集団戦法に頼っているのとは対照的です。

Amazonではエンジニアのことを忍者と呼ぶことがありますが、単に外国人の興味を引くということだけでなく、この呼び方はエンジニアの職務を表現する上で非常にマッチしていると考えます。*2

取扱商品数の拡充等で成長を続けるオンラインストアだけでなく、最先端クラウド技術を活かしたAmazon Web ServicesAWS)の展開と、さらなる挑戦を続けるAmazon。その影の存在でありながら凄いことをするという思いを込め、Amazonエンジニアは自分達を忍者Ninja)と呼びます。

Amazon エンジニアキャリア採用サイト

army of traveling Code Ninjas

AWS、プライム、キンドル、モバイルなどそれぞれの戦略を担当するチームの中で、エンジニア忍者のように裏方として活躍しています。これらの忍者たちは、必ずしも有名人とか大金持ちというわけではないですが、スキルを活かして、ビジネスの戦略を遂行する上で重要な役割を担っています。

もともと、忍者というものを生み出した国でありながら、日本のSI業界においては忍者のようにプログラマーが重用されることが少ないのが不思議なくらいです。大量の傭兵軍団からなる集団戦法を使って数で勝負というだけではなく、少数精鋭のメンバーで戦略的に勝つというようなやり方が、日本のユーザー企業でももっとポピュラーになれば、日本でも上級プログラマーの活躍する場所がもっと増えるのではないかと思いますし、こうした忍者衆をそばに抱えておけば、ユーザー企業にとってもITを本当にビジネスで活用する上で有効なのではないかと思いますがいかがでしょうか。

*1:実際には当時の忍者には上忍とか下忍とかの身分があり、服部半蔵のような有名な忍者が自分から現場で活躍したかどうかは疑わしいそうですが。

*2PGというと伝統的にモノづくり職人、鉄砲鍛冶、刀鍛冶の職人のイメージがありますが、最近はITで得られた情報から素早く次の作戦を遂行するという役割があるので、忍者はイメージとして合っているのではと思いますね。つまり、作戦の考案から実行まで、上流から下流までプロジェクトを素早くタイムリーに遂行するということです。

2012-01-25

ソフトウェア技術者軽視のシステム開発を続けるのはもう限界かもしれない

つい先日、富士通がグループで抱える3万人ものSEを再教育して、職務転換を行う計画であるというニュースを知りました。

富士通の3万人SE職務転換大作戦は成功するのか? - GoTheDistance

一つのシステムを複数の企業などが利用するクラウドサービスがこのまま普及すれば、顧客の要望を聞いて個別システムを作り込むSEは仕事がなくなり、余剰人員問題が顕在化するからだ。

クラウドの普及により、オーダーメイドでシステムをゼロから構築する必要がなくなり、そもそも顧客からの要件をまとめてシステムを設計するSEの仕事が不要になったり、基盤を構築、運用するエンジニアが不要になるということは、最近になってよく言われることであり、特に新しいことではありません。もちろん、クラウドの普及によって、これらの伝統的なSEの仕事が少なくなり、人員が余るという議論は間違いではないと思います。

ただし、一方でより本質的に重要なことは、クラウドの普及により、要件の定義から実現、運用までの期間が大幅に短縮できるようになったり、基盤構築など多くの仕事が自動化されることで、上流から下流まですべてを担当できるような真のソフトウェア技術者の役割がシステム開発で重要になってきているというところにあると思います。したがって、上流担当のSEだからといってプログラミング言語や基盤技術のことをまったく知らないといったことが許されない時代になってきているということであり、アメリカ的な意味でのプログラマーディベロッパー)の仕事がもっと重要になってきているということを理解する必要があります。プログラマーというと、単に設計書に従ってコードを打ち込む単純作業をする人や、逆にすごく難しい計算式とアルゴリズムを使うような研究者など、まったく異なるいろいろな職業を思い浮かべる人がいますが、少なくともグルーバルな意味でのエンタープライズ開発のコンテキストにおけるプログラマーとは、顧客の要件を素早く実現する方法を提案して、そのまま構築し、場合によってはテスト自動化やデプロイメントまで担当する人のことを指します。そういう意味では当然上流も下流もありません。もちろん、経験やスキルによって下級プログラマーから最上級のプリンシパルプログラマーまで幅はありますが、上級職であっても、オブジェクト指向プログラミングができなくてよいということではなく、むしろお手本となるコードを書いたりコードレビューができることが求められます。

クラウド時代になったので、技術のわからない人でもシステムを構築できるということが時々聞かれます。もちろん、一部にはそのようなシステムもあるとはいえ、基幹業務やビジネスの中心にかかわるようなシステムであれば、クラウドを利用するとは言え、アイデアさえあればまったくの素人がシステムを構築できるとは考えるべきではないでしょう。この点については、ちょうど一年ほど前にも以下で議論しています。

日本のSI業界でこそ、専門の技術者の必要性がもっと見直されるべきではないのか? - 達人プログラマーを目指して

そういう意味において、ついに富士通のようなSIerも、今回の職務転換で今までのような上流偏重型の技術軽視の考え方を改め、

などの知識を持った専門家をついに育成することになるのかと期待したのですが、実情は大きく異なるようですね。

Weekly Memo:富士通が説くSIにおける人材革新のツボ - ITmedia エンタープライズ

 「これまでは、いわゆるモノづくりに焦点を当てた人材づくりを行ってきた。現在、SEが担っているスキルとしては、コンサルティングから入って、開発のためのプロジェクトマネジメント、業務アーキテクチャ、品質マネジメントITアーキテクチャ、プロダクトアーキテクチャ、そして運用・保守を行うサービスマネジメントがある。しかし、これからは顧客価値の実現に向けて顧客とともに考えていくという取り組みが一層求められるようになる」

 それが、図の上部に示されているところの「スキルからロールへのシフト」である。同社が新たな時代に向けて再定義したロール、すなわち「役割」に応じた職務は、「ビジネスプロデューサ」「フィールド・イノベータ」「コンサルタント」「サービスインテグレータ」の4つ。

もちろん、詳しい内容は分からないのですが、結局のところ、以前にもまして上流重視の方針のように思われます。*1残念ながら、富士通SEの職務転換先には、(アメリカ的な意味での)プログラマーもSDET*2クラウド基盤運用管理の専門家も含まれていないようです。

ところで、最近特許庁のシステム開発中断という以下のニュースも話題になっています。

朝日新聞デジタル:どんなコンテンツをお探しですか?

調査報告書 平成22年8月20日 特許庁情報システムに関する調査委員会

特許庁の情報システムについて - myatsumoto blog

5年も前からずっと設計を行って結局完成しなかったということですが、その間コア機能を含む一部のサブシステムですら構築することはできなかったのでしょうか?このように何年もかけて上流の設計を続けても、まともなシステムが一つも完成しないという話は特許庁に限ったことではなく、メガバンクの基幹システム構築などいたるところで耳にします。そもそも設計に5年もかけていては、技術の内容もビジネスの内容も大きく変化してしまうわけでウォーターフォール的に設計を固定できるわけがないですし、仮になんとか完成にこぎつけたとしても使い物にならないシステムができるだけだと思います。

プログラマーの自分の目から見て、いつも非常に不思議に思うのは、こういった問題が起こった場合、

  • 管理の方法が悪かった
  • 顧客との仕様の調整がうまくいかなかった
  • 上流の基本設計がうまくまとまらなかった

というような話は出てくるのですが、決してプログラムや基盤の設計が原因とされることがないということですね。実際にはこういった実装面の問題は全く無視できるはずはなく、コピーアンドペーストだらけで複雑になり、まったく手が付けられなくなったり、あまりにも性能が悪くて要件が満たせないというような問題はよほど簡単なシステムでもない限り大きな問題となるはずです。(プログラミングと設計は本来切り離せないものなのでは - 達人プログラマーを目指して

伝統的に、日本のSI業界ではその構造から実装、構築の作業を軽視する傾向があったわけですが、いい加減にこのような考え方でシステム開発を続けることは品質やコスト、スピードの面でもう限界に達していると考えられるのではないでしょうか。

富士通のようなSIerSEの職種転換を目指すのであれば、単に上流のコンサルタントだけでなく、上級の開発者の仕事をもっと重視すべきなのです。もちろん、そのためにはござ先輩も書いているようにSIerビジネスモデルの大変革が必要だと思いますが。あるいは、ユーザー企業がもっと率先して上級のプログラマーを雇ってより短期間で効率よくシステムを開発できるようになるべきかもしれません。その場合、SIerは文字通りシステム統合の手助けとか、開発基盤の提供など、ビジネスモデルなどではなく、より開発のインフラよりの部分を担当する役割を担うことになると思います。

*1:成果物がExcel方眼紙からパワーポイントになるという意味ではスキルの転換が必要かもしれませんが。

*2:Software Development Engineer in Test、テスト自動化などの専門家