主に言語とシステム開発に関して RSSフィード



2012-02-13

AndroidアプリにStrutsのようなコントローラを導入し,画面制御させるサンプルコード (の試作品。バリデーションやビジネスロジックの骨組み)

|


Androidアプリの設計に,Strutsのようなアーキテクチャを取り入れよう。という記事。


ただし,Javaにつきものの「XML地獄」は,徹底的に避けるものとする。

いかにシンプルにAndroidアプリの画面制御を管理するか?



Androidアプリは,複数の「Activity」(=画面)を持つ。

それらActivityどうしの間を行き来するためには,Intentを発行する。


通常,Intentの発行処理は,遷移元のActivityの中に書いてしまう。

Activityの中に,遷移元と遷移先の情報が埋め込まれるのだ。

そうすると,下記のような「密な結合」が生じてしまう。

f:id:language_and_engineering:20120214012536p:image

なんとも網目状で,カオスな結合状態だ。

これは,オブジェクト指向的にはダメである。

疎結合」なクラス設計になっていない。


むしろ,Activityにはそういった情報を埋め込まずに,

画面遷移に関る処理を集約して,1つの「コントローラ」クラスに任せる。

すると,下記のような「スター状」の結合になる。

f:id:language_and_engineering:20120214012537p:image

ビューと制御の分離である。

コントローラクラスは,制御について責任を負う。バリデーションなども引き受ける。

Activityは,個別の画面におけるUI描画・イベントのハンドリングなどについて責任を負う。



どちらがよい設計か?

小規模アプリなら,前者で事足りる。


しかし規模が複雑になってくると,画面制御の洗い出しに苦労するものだ。

そして,思わぬところに画面遷移の実装漏れ・不整合が見つかったりして,テスト工程の負荷が予想外に増える。



ちょうど,Strutsフレームワークで,struts-config.xmlが

画面遷移やフォームのバリデーションに関する設定を引き受けていたのを思い出そう。


同じように,Androidアプリの「コントローラ層」の情報の集約を行なうことで

アプリ開発の保守性・生産性・拡張性・テスタビリティ等を向上させたい。



そのようなサンプルコードが完成し,Android実機上で実際に動作した。

試作品のレベルだが,下記で紹介する。


(1)コントローラ層を簡潔に,シンプルにコーディング

DSLを提供するライブラリを無視すると,ユーザが手を触れるのは,わずかな量のコードだ。

以下の4つだけ。

  • アクティビティ本体
  • コントローラ
  • バリデータ
  • ビジネスロジック

続きを読む

2012-02-12

わたしのSVNコミットログ 語録集

|


私がソフトウェア開発で,SVNやGitなどのバージョン管理ツールを使う際,

ふだんコミットログとして残しているコメント内容のパターン。


何となくほのぼのするコメントのみを一部抜粋。


語録集

個人的には,下記のようなコミットログを残す。


おつかれ


おちかれ


自分乙

続きを読む

2012-02-10

Androidアプリの画面レイアウトを,まるでjQueryのようなコードで動的構築できるライブラリ (の試作品。UIコーディングのためのDSL)

|


まるでjQueryのような簡潔なコードによって,

AndroidアプリのUI・レイアウトをコーディングできるようなJavaライブラリ。


その試作に成功した。


アクティビティ中で,下記のようなコードが書ける。



  // 動的に定義したViewは,これらのフィールドに代入される。
  MButton button1;
  MLinearLayout layout1;
  MTextView tv1;
  MEditText et1;
    

  @Override
  public void onCreate(Bundle savedInstanceState) 
  {
    super.onCreate(savedInstanceState);


    // レイアウトを動的に描画する。
    
    new UIBuilder(context)
      .add(

          // Buttonを定義
          button1 = new MButton(context)
            .text("ボタン1")
            .click(new OnClickListener(){ // クリックイベント

              @Override
              public void onClick(View v) {
                // イベント発生時,他のViewの値を参照可能
                Toast.makeText(
                  context, 
                  "ボタン1が押されました。入力値:" + et1.getText(),
                  Toast.LENGTH_LONG
                ).show();
              }

            })
      )
      .add(

          // LinearLayoutを定義
          layout1 = new MLinearLayout(context)
            .orientationHorizontal() // 水平に並べる
            .widthFillParent()
            .add(

                // TextViewを定義
                tv1 = new MTextView(context)
                  .text("ラベル" )
                  .widthWrapContent()
                ,

                // EditTextを定義
                et1 = new MEditText(context)
                  .widthPx(200)

            )
      )
    .display(); // 表示する

  }


上記のコードを実行すると,下記の画面キャプチャのようなレイアウトとなる。

f:id:language_and_engineering:20120211003009p:image


ガチガチの静的型付け言語である Java 上であるにも関らず,

バリバリの動的言語である JavaScriptjQuery っぽいコーディングができる。

少し夢みたいな話だ。


しかし,これは現に実現した。


このライブラリの基本的なアイデア,およびその内部のコードの一部抜粋を,下記に記載する。


着想・企画

Androidアプリを開発する際,レイアウトXMLをチマチマ編集するのは,極めて面倒だ。

続きを読む

2012-02-09

制御しやすい「デバッグ用ロガー」を自作して,サクサク開発 (Javaで,メソッド名を含めログ出力する方法のサンプル)

|


開発中,デバッグ用のログ出力機能は,できるだけ役立って欲しい。

プログラマにとって役立つような情報を,最大限のボリュームまで引き出してログ出力したい。


そのために,Javaで簡易ロガーを自作する際,

下記の2つの要素を駆使してみるのはどうか?

  • スタックトレースAPI
  • 独自アノテーション

スタックトレースを使えば,ログ出力しようとしているオブジェクト自身の情報が分かる。*1

つまり,「呼び出し元」のクラス名やメソッド名を,ログに記載できる。

(これは,Log4jをラップする独自ロガークラスなんかを作った時,よく初回で苦戦する罠だろう。)


また,独自アノテーションを定義すれば,

特定のクラスや特定のメソッドに対して,自由に「メタ属性」を付与できる。

その属性を見ることによって,クラスやメソッドの振る舞いを容易に制御できる。

  • このクラスはもう十分,単体テスト済みなので,このクラスだけはデバッグログを出さないようにしたい。」

とか。

そうすれば,結合レベルの試験段階で,作業負荷を軽減できる見込みがある。



上記の指針に基づいて,ごくシンプルなクラス設計を行ない,

下記にサンプルコードと実行結果を示す。


※また末尾には,おまけとして,ラテン語の小ネタを掲載する。


サンプルコード

主要な役者となるクラスは,3つ。

  • メイン処理
  • 独自ロガー
  • 独自アノテーション

続きを読む

*1JavaScriptでいうと,arguments.callee.callerみたいなものだ。残念ながらJSでは,Functionオブジェクトの名前までは取得できないし,関数のレシーバを参照するすべも無いが…。

2012-02-05

Javaの非同期処理を,シングルスレッドのようにシンプルにコーディングするための設計パターン (並列処理を逐次処理にする)

|


マルチスレッドの処理を,シングルスレッドであるかのようにコーディングしたい場合がある。

1番目の非同期タスクの処理結果を,2番目の非同期タスクが利用する場合など。


つまり,並列化されたタスクを,取扱い上は「逐次化」したいのだ。


まずは手っ取り早く,やりたい事をUMLで表現しよう。


「非同期タスクの連鎖」を実装する際,

しばしば下記のような「コールバックの入れ子」が生まれる。

f:id:language_and_engineering:20120206084434p:image

その結果,メインの処理フローが見失われてしまう

「非同期タスクが連鎖している」という状況が,ソースコードから一目で伝わらないのだ。


この状況を改善するために,下記のようなシーケンス図に作り変えたい。

f:id:language_and_engineering:20120206084435p:image

※ダイアグラム中で,矢印の先っぽが「同期呼び出し」と「非同期呼び出し」の違いを表している点に注意。


こうすれば,「非同期タスクが連鎖している」という状況が,ソースコードからも,クラス設計からも,一目で伝わるようになる。

メインの処理フローが,明示的にわかるようになるのだ。

そうすれば設計しやすくなり,実装しやすくなり,テストしやすくなり,保守しやすくなる。



加えて,後者の方がよりオブジェクト指向な設計だ。

  • 個々のタスク自身は,自分自身のタスクに専念すればよい。(Mind your own Business!)
  • どのタスクがどの順番で呼ばれるか?どう連携させるか?といった「制御フロー」に関する情報は,制御用の親クラスに任せる。(いわば,タスクマネージャ

残念ながら,前者の「コールバックの入れ子が延々と続くので,処理を追いかけづらい」スタイルのコードのほうを,よく見かけるのでは。

この点は,JavaやJavaScriptなど,非同期タスクをサポートしているプログラミング言語であれば何でも問題になり得る*1


Javaの場合,言語レベルでsynchronizedブロックをサポートしているため,

  • スレッド間で「同期」を取れば簡単では?

と思うかもしれない。

しかし,synchronizedは乱用できるものではない。安易に使うとデッドロックを生むので,慎重な考察が必要になる。


ここでは,Javaで「synchronized」キーワードを使わずに,

複数の非同期タスクを「逐次的」にコーディングする方法を示す。


まず,「逐次的」とはどういうものか説明する。

そして,上述の「タスクマネージャ型」のシーケンス図に倣い,Javaでのマルチスレッド・プログラミングのコードをシンプルにするような設計技法を1つ示す。

  • (1)処理の「逐次化」とは?
  • (2)JavaScriptでの「逐次化」の具体例
  • (3)Javaでの「並列化」がスパゲッティコードを生みかねない例
  • (4)Javaで,複数の非同期タスクを「逐次化」する設計パターン例

(1)処理の「逐次化」とは?

続きを読む

*1JavaScriptを例に挙げたが,Javaと違ってJavaScriptがシングルスレッドである,という事実はお忘れなく。 http://d.hatena.ne.jp/language_and_engineering/20090614/p1