Hatena::ブログ(Diary)

mizchi log

@mizchiの雑記帳

2011-08-31

はじめてのしゅうだんかいはつ あるいはAndroidの暗黙知のこと


先月ぐらいからバイトでAndroidのプログラムを書いている。
結構、言葉になってない暗黙知がたくさんあったので、その経験として、メモを残す。プログラミングそのものの話も含む。

三人で分担して開発していた。

分担
自分: Android開発初心者。プログラミングはある程度慣れてる。ロジックとネットワークとバックグラウンド処理
A : Android開発初心者。iPhoneアプリ開発経験ありだが、プログラミングは慣れてない。AndroidのUIデザイン担当
B : サーバー・データベース担当。PHP結構出来る。

問題。このバイト先ではAndroid開発経験者がいない。スキル的にも自分より上の人が最初はいなかった。途中で入ってきたスキルがある人がいたが、このプロジェクトには関わっていない。というわけで、自分とAがほぼゼロから開発してきたことになる。
かなり時間がかかっていて、あまり開発効率がよかったとは言えない。あくまで経験として自分は割り切っていた。社長はそうじゃないっぽいが。まあそのうちリリースする。


BとはネットワークでHTTPでJSONをもらうだけの関係。最初にアクセス用のクラスを書いて、あとはそのテストコードを定期的に確認していた。自分はアクセスログだけ見せてもらっている。このクラスはAndroidに依存しなかったので、Groovyでテストを書いた。

で、自分とAが結構密接に連携してて、Bがほとんど初心者だったので、彼の描いたコードを自分がリファクタリングしたり、いろいろ口をだしていた。
とはいっても、ちなみに自分もAndroid開発経験がはじめての初心者なのだけど、まあコードを書いてきた経験はあるので、それ任せで力押しの開発だった。Java、大学の授業で習って以来だった。

とにかくフィールドメンバを減らす コードを短くする


共同開発だと、どこに触れてどこに触らないかを明確にする必要がある
「全部フィールドにすると便利」「全部staticだと便利」は甘え。なんでもかんでもpublic staticにしない。挙動を変えない限りで、ひとつひとつフィールドメンバから落としていく。
クラスのstaticメンバにするとしたら、初期化をきっちりと行う。アクセス時にnullであるとエラーが起こる。フィールドメンバの初期化だけはきっちり。
フィールドメンバは、フィールドメンバにする必要性が生じたときに、はじめてフィールドメンバにする。

自分の開発経験的に、Java自身への習熟で、どれだけフィールドメンバを減らせるか、短く簡潔なコードにできるか変わっていった。基礎が大事。

同じコードを二度書かないという強い決意

共通に何度も出現するルーチンを関数に押し込める。短いコードほど潜在的なバグが減る。
短くすることが目的になってはならないが、それでも短いコードを書くという強い意思が必要。

コピペを自分の色に染めること

ネットから拾ってきたコードは、独立して動くように書き換える。外部に依存する部分をコードを切り落とす。
フィールドメンバは可能な限り除去する。ネットに転がってるJavaのサンプルコードは、不必要なフィールドメンバがあることが多い。
中身の挙動がわからなくても、副作用がないように、メソッドの中に押しこんで抽象化してしまう。

ダミーデータ

多少面倒でも、ダミーデータを最初に準備しておくと開発が進む。そしてダミーデータの形式をきっちりクラスで決めしまうといい。
サーバー側が常に正しい挙動をしているとは限らない。サーバー側がCakePHPだったっぽいのだけど、何かの動作を試すと何かのControllerエラーで頻繁にバグってた。

今回のプロジェクトはサバクラ型なので、ダミーデータのjsonを吐くようにしたので、サーバー側が落ちてても開発が進んだ。
しかしダミーデータに固執してはいけない。将来的に必要な拡張の余地は残しておく。

で、実際のどうなるか

共通パーツに切り離せないものは、無名クラスに押し込んでしまえばいい、って話になった。

非同期でTwitter#getTimeline(int uid)という操作でJSONObjectを取得したいとする(実際はそんなコードではないけど、サンプルとして)

class TwitterTimelineView extends Activity{
//...
   private LinearLayout mainw;
   private ProgressDialog dialog;

   @Override public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState); 
         mainw = new LinearLayout();
         dialog = new ProgressDialog(this);
         setContentView(mainw);
   }
   public void onStart(){
     super.onStart();
     final int uid = 321431;
     new AsyncTask<Integer,Integer,JSONObject>() {
            protected void onPreExecute() {
                dialog = MainActivity.dialog;
                dialog.setTitle("Now Loading...");
                dialog.show();
            };
            protected JSONObject doInBackground(Integer... params) {
                return Twitter.getTimeline(uid);  // 時間がかかる操作
            }

            protected void onPostExecute(JSONObject json) {
                Log.d("DEBUG","AsyncTask "+json.toString());
                mainw.addView( getTimelineView(json));
                dialog.dismiss();
            }
        }.execute();
    }

    private LinearLayout getTimelineView( JSONObject json ){
          // jsonのデータを分解してパラメータをセットしたviewをつくる
          return linearLayout;
    }
}

  • onStartなのは遷移してくるたびに更新したいから
  • mainw がフィールドメンバなのは、初期化用にとりあえず見せておき、非同期タスクからonCreate以外の名前空間から触る必要があるため。
  • final int uid で引数を間接的に受け渡す。(実際のプロジェクトにはPreferenceから読み込んでいる)
  • 今回の非同期操作は使いきりなので、AsyncTaskを無名クラスで宣言して、そのままexecuteしてしまう。これをクラスにしたりすると、無駄にクラスが増えてややこしくなる。
  • もし非同期のアラート画面を自作したり、細かなオプションを付けて何度も使うのなら、クラスとして独立させる。
  • 非同期タスクを飛ばす前に、非同期タスクから触れるフィールドメンバが、必ず初期化されていることを確認する。
  • getTimelineView では、フィールドメンバにアクセスしない。極端な話フィールドメンバをnullで埋める可能性がある場合、あとの動作が動く保証がない。
  • 正直mainwという名前は良くないかな…


「ほとんど共通パーツで部分が違うもの」をメソッド化する。
必要以上にファイルを増やさない。増やしすぎると、どこにアクセスしていいかわからない。
連番ファイルはやめる。不必要にlayoutのxmlを増やさない。
Myなんとかって、テストコードじゃないんだからそういう意味が分からない名前は付けない。

デバッグ用のLogは便利だが使い終わったら破棄する。放置すると、どこでのLogなのかわからなくなる。それでタグを増やしたりすると本末転倒。

Android特有の問題

なにのコンストラクタか、どのApplicationContextか、で初期化されてるものが変わってくる。thisとは何か?を常に意識する。
デバッグするときは、何が初期化されてて、何が初期化されてないかを常に気にする必要がある。

テストコード

最初にテストコードを書くべきだったとは思うが、手探りの開発の場合、そもそも前が見えないので、テストコードに縛られると、それに縛られて開発が停滞する。そもそもテストコードなんて書けないと思われる。
見通しがたった時点で、中途でテストコードを書く習慣をつけること。

git

開発メンバー誰もgitに慣れてなかった。
git自身の操作に振り回されるので、gitの練習と割りきって、手動でバックアップしつつmergeに挑むこと。merge失敗しても泣かない。出来る限りコンフリクトを減らしたいので、変更分が少ないときは目視でmergeしていた。あんまりgitの恩恵を受けていない…。次のプロジェクトではRedmineを使う。


まとまってないけど、これはペアプロで話していた内容を思い出して、そのまま頭の中身を吐き出したもの。

というわけで、今回のプロジェクトはテスト的な意味合いが強かったので、次に生かせるように、自分も含めてできるだけアジャイルな環境が作れるような種を蒔いた。
でも、これ以上Android触れたい気分じゃない。まだこのプロジェクト終わってないけど!

2011-06-15

Android Eclipse メモ


Androidアプリを作ってて、いじった箇所メモ

補完のトリガーを[ shift - Space ]に


Preference - General - Keys - Content Assist


黒背景にした


いじる箇所は二つ

  • Preference - General - Editor - Text Editors
  • Java - Editors - Syntax Coloring


いじってみると案外と修正箇所多くて辛いので、別にこだわりがないなら必要ない

ユニットテスト


JUnitとEclipseを使って学ぶ、“テスト”の常識 (1/4) - @ITGH
AndroidアプリケーションをJUnitでテストする | Android開発メモ


Androidでのテスト、最初めんどかったけど一度書いたら使いまわせるので一回チュートリアル通りにやりましょう

Gitを使う

EGitを使ってEclipseでGitリポジトリを操作する | ITEMAN Blog - アイテマンブログ

リポジトリを作成

Project Root で右クリック - Team - Share Project - Git - create - Finish

最初のコミットまで

Project Root で右クリック - Team - add to Version Control - [管理するファイルを選択する] - Commit - [コミットメッセージを書く]

ブランチを切る

右クリック - Team - new Branch - [ブランチ名を入力] - check out


あとはこれ読む
EGit/User Guide - Eclipsepedia

Vim キーバインド


Eclipseのキーバインドをvim風にできるVrapperが素晴らしすぎる件について - ゆろよろ日記 をそのまま適用した。
.vrapperrc もコピペ、もとい参考にさせていだきました

2011-01-15

sbtでscala-android (SDK r8)


r8から android target listのバージョン指定の書式が変わってるのでめんどい

$ brew install sbt # or other way
$ cd ~/bin
$ wget --no-check-certificate https://github.com/jberkel/android-plugin/raw/master/script/create_project
$ chmod +x create_project
$ export ANDROID_SDK_HOME=/Users/mzi/android-sdk
$ ln -s /Users/mzi/android-sdk/platform-tools/adb /Users/mzi/android-sdk/tools/
$ ./create_project HelloAndroid org.mizchi.helloandroid --platform android-8 --scala-version 2.8.0.RC7 --activity HelloAndroid
$ vim platform/build/HelloAndroid.scala # Android-2.1 => Android-8(if target is android2.2 cf.android target list )
$ sbt
> compile
> install-device


なんか色々面倒ですね!!!!!

Android SDK r8 でadbやら色々入ってない件


久しぶりにAndroidアプリでもつくるかーとandroid create project ほにゃららしようとしたら、jarがないと言われたのが発端
homebrewでSDK更新したら日常的に使っているadbが消えて発狂した
homebrewのandroid-sdkがおかしかったので、formulaを削除して公式から入れ直したら公式が元々おかしかったという有様だった

解決


ググったところ adb は platform-tools 以下に移動したよーとのことだったが、そもそも android-sdk-mac_86 には そんなディレクトリない
で、コマンドから更新してみる

$ tools/android update sdk

(10分ぐらいかかる)

adb is updated! と言われる。他にも色々と出現
たぶん r7からの差分しか入ってなかったのではないだろか
昔からここらへんはちょっとおかしいらしい