2012年1月12日木曜日

AppEngine Office Hourに参加した。

Japanese AppEngine Office Hourに参加したので、そこでの質問と回答をメモ
https://plus.google.com/u/0/110554344789668969711/posts/d3ykURrCnDt

Python2.5以下でないとssl警告が出る件
→Goのappcfg.pyはpython2.5が指定されているので、
$ python ../appcfg.py update app
など、python新しいバージョンのPythonを明示的に指定すると、警告はでない。
または、python2.5の方にsslモジュールを適用する。

ユーザ名を取得する場合。
初回ログイン時に表示名を入力するなどしてもらって、表示名を入手する。
ATNDとかどうだったかな…?
→多分、同じ動作をさせていると思われる。
→確認したらユーザ設定画面があって、そこでユーザ名を登録していた。

Emailの先頭部分(@以前)を表示
→だと、メールアドレスがバレてしまうので…。
上記の対応を行うしか無いだろう。

Java、PythonもNicknameを取得すると、メールアドレスの先頭部分が取れるかも。

Goを使うメリット
・ネイティブであるので、立ち上がりが一番速い。メモリの効率も良い。

XGTransactionの最大エンティティグループについて(仕様で最大5グループまで)
http://code.google.com/intl/en/appengine/docs/go/datastore/overview.html#Cross_Group_Transactions

開発環境でHRDのオプションを入れるコマンド
$ python ../dev_appserver.py --high_replication ./app


2012年1月11日水曜日

Support Packageを使ってFragmentを利用する

先日、私が公開している「サポセン前の問診票」アプリケーションにFragmentを適用した
形に作り替えたので、その時に発生した現象と、Framgentの使い方をメモしておきます。

前提:
※Support Package v4を利用する。

以下が大体の手順です。

  1. レイアウトXMLにFragmentを含むレイアウトを定義する。
  2. FragmentActivityを継承したActivityのクラスを作成する。
  3. 普通に起動。


だけです。終わり。というと内容が薄いので、

レイアウトは以下のような感じになります。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <FrameLayout
        android:id="@+id/framelayoutmain"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
     <fragment
         android:id="@+id/fragment1"
         android:name="com.sample.ui.MainFragment"
         android:layout_width="fill_parent" android:layout_height="fill_parent" />

    </FrameLayout>
</LinearLayout>

Activityのソースコードはこれまで通りとなります。

public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

Activityが実行された時点でFragmentも呼び出されて表示されますので、
Fragment外で処理する事が無ければ、Activity側では何も記述しなくても良いです。
ポイントとしてはFragmentActivityを継承しないと実行時にエラーになってしまいます。

あとは、Fragmentのプログラムの方で処理するプログラムを
実装すれば良いです。

次に、FragmentをBackStackに積む方法は以下のコードです。

SubFragment fragment = new SubFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.framelayoutmain, fragment);
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
ft.addToBackStack(null);
ft.commit();

FragmentTransactionクラスがFragmentのBackStackの状態を管理しているようです。
ft.replaceでレイアウトに配置されているFragmentを置き換えます。
これは、Fragmentが複数配置されている場合でも、それぞれのFragmentが配置されているViewを指定して置き換える事ができます。
setTransitionは置き換え時のアニメーションを指定します。
addToBackStackは置き換え後の状態(アクティビティ全体)をBackStackに積みます。
最後にcommitを実行して確定します。

注意点として、ft.replaceした場合、下にあるFragmentの内容が見えてしまいます。
(背景が透明になる)
したがって、背景を画像や色を指定して、下のFragmentが見えないようにしないと
いけません。(これはSupport Packageのみの現象?)
しかも、ListFragmentを利用した時(他のFragmentでも?)、画面をタッチすると、下に配置されたFragmentもタッチを検出しますので、処理が実行されてしまいます。
BackStackに積む前に下のFragmentの処理が実行されないようにEnabled = falseにするか、
getFragmentManager().getBackStackEntryCount()をチェックして、積まれていたら
処理をスキップするなど工夫をしないといけないようです。

Google+に書き残したコメントです。

https://plus.google.com/u/0/114183076079015753160/posts/cyodhHmgRy9
https://plus.google.com/u/0/114183076079015753160/posts/3kDyzNe1mej
https://plus.google.com/u/0/114183076079015753160/posts/UHcTUgp7Hky

Slim3 Source Code Reading #3

Slim3ソースコード読書会(3)を開催しました。

今回は、前回のPutとかぶっていますが、以下のソースコードを読みました。
Datastore.java
DatastoreDelegate.java
AsyncDatastoreDelegate.java
ModelQuery.java
AbstractQuery.java
DatastoreUtil.java

そこで話題になったポイントをメモしておきます。

1点目。
AsyncDatastoreDelegate.javaの642行目で、

mm.validateKey(key);を呼び出し、KeyのKindとModelMetaで保持しているKindを
比較し、一致しなければIllegalArgumentExceptionをスローしている件。

これは、以下のように、取得しようとしているModelとKeyが一致しない時などに、
エラーにするための防波堤ではないか。という結論になりました。

例えば、以下のようにTweetクラスとTweet2クラスが存在したとして、
プロパティの構成が全く同じ場合で、データストアにKeyが存在している場合。

Tweet tweet = new Tweet();
Datastore.put(tweet);
Tweet2 tweet2 = Datastore.get(Tweet2.class, tweet.getKey());    // 指定したKeyとModelが不一致

データストアからのGetは成功しますから、構成が同じであれば、Tweet2クラスの
Modelとして値が取得されます。しかし、これは本来Tweetのデータであるため、
Modelが取れてはいけないのですが、データストアの仕組み上防ぐことができません。
したがって、ModelMetaで定義しているKindとKeyのKindを比較して一致しているか
どうかを確認していると思われます。

2点目。
ModelQuery.javaの241行目のasList()で最後にfilterInMemory()とsortInMemory()を
呼び出していることについて。

最初は、「DatastoreのQueryでsortやFilterを指定したらメモリ上でのソートやFilterは不要だろう」と
いう意見だったのですが、よく読んでみると、呼び出し元でfilterInMemory()を
呼び出していなければ、inMemoryCriteriaのSizeが0なので、実際には
Filter処理は実行されません。同様に、sortに関してもinMemorySortCriteriaの
Sizeが0であればSort処理も実行されません。

ただし、データストアでSortを実行したあと、sortInMemoryを呼び出していれば、
両方とも実行されることになります。

恐らく、inMemoryFilterについてはOR条件で抽出したい場合があれば、
それを実現するために利用するのではないかという結論になりました。
(AND条件での検索であれば、QueryにFilterを設定するだけで良いが、データストアでOR条件は指定できない。)

次回は1/17(火)19:00〜の予定です。

2012年1月10日火曜日

Slim3 Source Code Reading #3の前に(その2)

午前中にGetについての記事を書いたのですが、
Queryについてもメモを残しておきたいと思います。

実はQueryについては読む予定は無かったのですが、
開発環境での問題なのか、Putした結果が反映されるのが遅いという現象が
発生したので、Datastore.query(t).asList();という書き方がおかしいのか?と
思って、読み進めてみました。
実際はGetと同じくデータストアの読み取りなのでこちらも読んでおくべきと
思ったのでメモしておく事にします。

先に概要をメモ

  • Datastore.query(class)を呼び出すとDatastore.java3965行目が呼び出される。
    • 中ではDatastoreDelegate.query(class)を呼び出すので、DatastoreDelegate.java2397行目が実行される。
      • この中身はAsyncDatastoreDelegate.query(class)を呼び出すだけ。
        • AsyncDatastoreDelegate.java1940行目が実行される。
          • 中身はModelQueryクラスのインスタンスを生成してreturn
            • コンストラクタの引数は、AsyncDatastoreServiceとModelMetaクラス
            • ModelQueryクラスのコンストラクタでappengineAPIのQueryクラスを生成する。
まとめると、「Datastore.query()はModelMetaで指定したKind名のQuery」を生成する。
という簡単なものでした。

では、asList()メソッドを呼び出すとどうなるか。
ModelQuery.java241行目が呼び出されます。

最初にappengineAPIのPreparedQuery#asList(options)が呼び出され、結果が返ります。(トランザクションがセットされていればトランザクションも使われます)

そして、PreparedQuery#asList()で取得された結果(Entity)をModelMetaに変換し、
ModelMetaからModelクラスへの変換を行います。(取得された件数分全て)
ここで、Model#postGet()も呼び出されますので、このタイミングで編集処理が
実行されます。
よって、データ数が多いときには、適切にLimit指定を行わないと、
「表示しない(使わない)データを処理する」ことになるケースもあるということになります。

Slim3 Source Code Reading #3の前に

本日、Slim3 Source Code Reading #3を開催します。

恐らく、今日はGetとTransactionを読む予定になると思いますが、
Queryについても読み進めておく必要がありそうです。

まず、Getから。
GetはDatastore.java835行目の
public static <M> M get(Class<M> modelClass, Key key)
から読み進める事になると思います。

getメソッドの中では、メンバに持っているDatastoreDelegate#getが呼び出されます。(838行目)
これは、putの時と同じです。

DatastoreDelegate#getはいくつかメソッドがありますが、
748行目→769行目→771行目でカレントのトランザクションを取得し、
カレントのトランザクションを利用して1099行目を呼び出します。

1099行目のgetも、中身は非同期のgetAsync()を呼び出すだけです。
return FutureUtil.getQuietly(async.getAsync(tx, modelMeta, key));

FutureUtil.getQuietly()はFuture#get()を呼び出し、非同期の結果を受け取る+例外をキャッチするのみですので、結局「非同期で処理されるのを待つ」という感じでしょうか。
(これは2回目で読んだPutと同じです)

async変数はAsyncDatastoreDelegateクラスなのでそちらに進みます。

AsyncDatastoreDelegate#getAsync()はAsyncDatastoreDelegate.javaの630行目に
あります。
この中では、560行目のgetAsync()をwrapしているだけです。
560行目のgetAsync()は、中で1439行目のgetAsMapAsync()を呼び出します。
ここでは、DatastoreUtil#getAsMapAsync()を呼び出しているだけです。
DatastoreUtil#getAsMapAsync()はAsyncDatastoreService.getを呼び出し、データストアから実際に読み取ります。

ここまでの流れです。

  • Datastore#get()からDatastoreDelegate#get()を呼び出す
    • 748→769→771で、カレントのトランザクションを取得し、1099行目
      • FutureUtil.getQuietly(async.getAsync())
        • AsyncDatastoreDelegate.javaの630→560
          • 1439行目のgetAsMapAsync()を呼び出す。
            • DatastoreUtil.getAsMapAsync()を呼び出す。
              • AsyncDatastoreService#get(tx, keys)
まとめると、カレントのトランザクションで非同期APIを呼び、データストアからエンティティを呼び出す。

エンティティ→modelへの変換はAsyncDatastoreDelegateの640行目で
行われています。
この時点で、データストアから読みだしたタイミングで値を編集するpostGet()も呼び出されます。

明日以降の授業の準備もあるので、今日はここまで。

2012年1月3日火曜日

2012年の目標

明日(というか、今日)で正月3日間が終わるので、
そろそろ目標を決めていきたいと思います。

※まとめていたら長文になってしまいました。

毎年、目標を設定しても暑くなる頃には頭から消えてしまうわけですが、
昨年(2011年)の実績ではいい感じだったので、今年も書いてみることにします。

まず、中国GTUGの活動について。

確定事項として、

  1. オープンセミナー@広島での発表(1/21(土))
  2. 岡山在住の技術者の方に中国GTUGスタッフのお願いをする。
  3. 第12回勉強会@岡山
1つ目のオープンセミナー@広島に関しては以下のGoogle+のコメントを参照して下さい。
https://plus.google.com/u/0/114183076079015753160/posts/eSTnHeY7cfm

2つ目のスタッフについては、私の仕事関係がうまくいかなくなる(仕事がなくなる)
可能性が非常に高いので、岡山で私以外の方にも開催に関して
手伝っていただかないといけなくなる事を想定しました。
これまで私一人で準備していた部分をお願いしようと思っています。
(広島には2人の方にお願いしています。場所の確保が主な内容のつもりです)

参考までに。
スタッフとしてお願いする条件を個人的に決めていました。

  1. 他のコミュニティのスタッフを兼任していない方
  2. 1に該当しない方で、ある程度制御が効きそうな方。
  3. 中国GTUGの運営ルールに則って活動していただけそうな方
2と3は現時点では私の運営の考え方に反しない方になってしまっているのですが
1が最も重要なポイントだと思います。
スタッフの方には、ある程度イベントの開催の許可をしようと思っているのですが
兼任していると、例えば、「共催」という形でGoogle技術を扱わないような
イベントを開催されたりする可能性を考えざるを得ません。

まだ、結成して1年半で、スタッフも私を含めてやっと3人という状態なので、
そこまで運営ルールというものを厳密にやりとりもしていません。
ということから、私が信頼できる方を厳選しているというのもあります。
(広島のスタッフの方は上記の2に該当する方ですが、怪しい事はしないと思ったので
お願いしました。それでも結成から1年経ってから(?)だったように思います)

これからスタッフのお願いをしようと思っている、岡山の方は、皆さん長い間
イベント等に参加していただいていますし、大丈夫だろうと思っています。

3つ目の第12回勉強会@岡山に関しては以下のサイトをごらんください
募集も開始しています。今回は初めての発表の方とリベンジの方にお願いしています。
https://sites.google.com/site/chugokugtug/event/12

次に、確定していない将来の予定(目標)

  1. Slim3 Source Code Readingの完走
  2. 広島でのイベントの開催
  3. ハッカソン、ハンズオン
  4. Source Code Readingの開催をする。
1と4については、新しい試みとしてソースコードの読書会をやってみようと思っています。
個人的に読めば良いのですが、せっかくなので。(イベントの開催ルールのためもあったりなかったり)Slim3 Source Code Readingについては今の所、結果は残していますが、カウントしていません。

2の広島での開催については、Twitterで希望の意見があったので、それも反映したいと思っています。
※OSCへの参加に関しては、私自身が参加する必要があるかどうかをじっくり考えたいと思っています。場所を提供していただけるのは非常にありがたいですが、私に問題があるのか、あまり交流が深まらなかったように思いましたので。
(活動資金の面の問題が解決すれば良いのですが、そうも言ってられないので)

3のハッカソンに関してですが、今年は「競技プログラミング系」で攻めてみたいと
思っています。もしくは、「研究」という感じで、Googleの提供するAPIを
叩いてみるとか、ライブラリを作るみたいなやつ。

昨年の意見として、「アイデア、チームを決める時間が作れないと難しい」と
いう意見がありました。

という事で、それを反映しようと思うと「個人戦でアイデア(仕様)が決まっている
もの」となるのかなと。

それはそれで本来の意味のハッカソンとなるのでおもしろいんじゃないかと思っています。
ハンズオンについても、要望があったりするので、考えたいと思っています。

次に仕事関係
まず、専門学校の授業。
2月中旬ぐらいまでは授業があるので、その対応。
できれば、生徒達の未来を決める or より良いものにする事をしたい。

その先は、オファーがあってから決まることなので未定。

という事で、学校の授業以外で収入のために何かしないといけないのですが、

  1. 執筆する
  2. GAEアプリの開発
  3. Chrome-Extensionの開発
  4. Androidアプリの開発
  5. バイトする
  6. 何か仕事を受託する

上から順番にやりたい気持ちは強いです。

執筆については、今年も挑戦したいです。私の書籍に関してのフィードバックは
そんなに多くないですが、”今の所”、否定的な意見は見えないので
個人的に色々反映して執筆したいですね。

GAEアプリの開発に関しては、自分自身がサイト運営をした事がないのと、GAEの課金関連でのチューニングなどの情報を得るためにはどうしても動かしてみるしか解決策がないのでやってみようかなと。
Adsenseの情報も見たいですし。(どうすればお金になるのか。とか)

最初のテーマは「イベント管理」で、GAE/Gで作成しています。
データを保証しませんが、適当に使ってみてください。

http://eventmanapp.appspot.com/


※Googleアカウントを利用してイベント参加申し込みができます。
※メールアドレスが見える可能性があります。(一応先頭3文字で切ってる気がする)
※キャンセルができません。(すみません、未実装です)
※イベントの削除もできません(すみません、これも未実装です)
※リマインダ機能もありません(すみません、これも未実装です)
※CSS適用していません。
※スマートフォンで参照したことは一度もありません。
※Billing設定をいれていません。多分どこかでエラーになります。
※適当にデータが消える可能性があります。(本当にイベントが登録されたら内容を見て考えます)

中国GTUGでの発表のネタの為にGoで作成してみたのですが、
今の問題点はNickNameが取れないのでメールアドレスしか表示できないという
致命的な問題にぶつかっています。これはSDKのバージョンアップに期待するしか
なさそうです。

Chrome-Extensionの開発もChrome Web Storeが出ているわけですし、
HTML5/CSS/JavaScriptの勉強も兼ねてやってみたいと思っています。

Androidアプリの開発ですが、使っていただいているユーザもいらっしゃるのと、
個人的に最後にやってみたい事があるので、その研究をするために、新規で1本。
現状のアプリケーションの更新を行いたいと思っています。

個人的な意見ですが、Googleの技術を使って収入にするのは「難しい」と思います。
が、アイデア次第で収益に繋がる事は十分わかりました。
後は、”アイデア”か、”問題を解決するための機能”があれば、(生活できるとは限らないが)がんばれるのかなと。

それからバイトですね。先日、親にも「何してでも生きて行けるだろう」と言われたので
本当に苦しくなったらバイトしようかなと思っています。
どうせなら未経験なものをやりたいですね。(何事も経験だと思うので。と言ってもこの年で言うことか?とも思いますが)
ただ、こうなったら中国GTUGの活動は多少あきらめないといけなさそうです。

最後に受託するということですが、昨年は「未払い」に悩まされたのと、苦労だけして
(技術的な経験にはなったのですが、)失う物の方が大きかったので、
これには手を出さないと思います。(ある程度信用の置ける方で、規模、難易度と相談して、聞くかもしれませんが)

最後に生活面ですが、

  1. スポーツクラブに通う
  2. Google+を使う
1.は昨年も行っていましたが、今年も引き続き。
2.は昨年まではTwitterによく投稿していましたが、今年からGoogle+を利用してみたいと考えています。個人的に自分のストリーム(TwitterでいうTimeLine)は全部見たいと
思うのですが、Twitterで全員をフォローすると、流れてしまって見れないという
状況になってしまったので、ある日からフォロー数を制限していたのですが、
Google+だとサークルの概念があるので、(Twitterにもリストがある事をちょっと前に知った)切り替えれば見れるなと。後は、投稿に対するコメントは投稿の下にでるので、
replyを見逃さなくて良いかなとか。
あとは、短縮URLを作らなくても良いとか。(複数のURLが貼れない(?)けど)
Twitterは基本Rom専と告知、スマートフォンからの位置情報の投稿にしようと思います。

長文になってしまいましたが、今年もGoogle技術を追いかけるつもりです。
昨年Googleのサービスを利用してみたら、確かに生活は便利になったので。
便利な使い方は紹介したいですね。(押し付けるわけでなく)
それから、Webの技術を勉強しようと思うとちょうどいい感じで絡んでくるので。

2012年1月2日月曜日

bytes.NewBufferの使い方

Go言語プログラミング入門でもURLFetchAPIを利用した例で出てきたのですが、
掲載しているソースコードだとあまり良くないので再度使い方をまとめておきます。

import "bytes"

var writedata = make([]byte, 0, length)
var writebuf = bytes.NewBuffer(writedata)

書籍では、make([]byte, length)を使っていますが、この意味は、"長さと容量がlengthのバッファ"が作成されます。

bytes.NewBufferを利用する場合は、長さは0で、容量が必要なサイズに設定されている事が望ましいとされています。

したがって、"長さは0"というのを明示するために上記の例にしなければいけません。

実際に、GAE/G SDK 1.6.1で実行してみると、0埋めされたデータが出力されていました。
Buffer.Write([]byte)は容量が足りない場合は、バッファの容量を増やしてくれるように
なっているので、var writedata = make([]byte, 0)でも良いかもしれません。
この場合、容量が0なので、容量を内部的に増やす処理(新しいバッファを確保して上書きコピー)が実行されるため
実行コストが増えてしまいます。