SlideShare una empresa de Scribd logo
1 de 124
Descargar para leer sin conexión
絶対落ちないアプリの作り方
DroidKaigi 2015/04/25
株式会社マナボ 白山 文彦 (@fushiroyama)
サンプルコード
https://github.com/srym/DroidKaigiSample
• 白山 文彦 (@fushiroyama)
• 株式会社マナボ (http://mana.bo/)
• Android
• Ruby on Rails
• DevOps
• Full Text Search
• 筋トレ
今日は絶対に落ちないアプリについて
考察してみたいと思います。
だがその前に伝えておきたことがある…
_人人人人人人人人人人_
> そんなものはない <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄
なんでAndroidアプリは
落ちる運命にあるのだろうか?
• バージョンが多種多様
• 端末が多種多様
• ベンダによる カスタマイズ
• 鬼門:カメラアプリ
• http://alpha.mixi.co.jp/entry/
2013/11572/ ※ここに苦労がまとまってます
• プログラマの無知と怠慢
• バージョンが多種多様
• 端末が多種多様
• ベンダによる カスタマイズ
• 鬼門:カメラアプリ
• http://alpha.mixi.co.jp/entry/
2013/11572/ ※ここに苦労がまとまってます
• プログラマの無知と怠慢
プログラマの無知と怠慢は
何とかしたい!
今日は短い時間なので
テーマを絞って話したいと思
います。
クラッシュのないアプリ作りの
スタートは、クラッシュの事実
に向き合うことから始まります。
https://crashlytics.com/
弊社のCrashlyticsで
実際にクラッシュの多いミスを
元に資料を作りました!
1. FragmentTransactionの取り扱いミス
2. ライフサイクルの終わったコントローラへの不正なアクセス
3. APIとの連携ミス
4. カメラアプリとの連携ミス
5. 大量の画像によるOutOfMemory
6. Activity/Fragmentの再生成・復元ミス などなど…
アジェンダ
• ライフサイクルの理解
• 非同期処理とコールバック
• Contextの正体
• Fragmentあれこれ
• Handlerの本質
• 静的解析を活かす
• 本当に落ちないことが本当に幸せか?
ライフサイクルの理解
ホントにホントに理解出来てる?
• Activityはユーザ操作等によって短期間
で頻繁に生き死にを繰り返す
• Activityの生死はプログラマが手出し出
来ない
• Activityが状態として死を迎えた時と、
実際にオブジェクトがGCされるタイミ
ングは違う
超・初級編:
onSaveInstanceState
onRestoreInstanceState
public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



startActivity(AnotherActivity.newIntent(this, "hello next intent"));

}

}
サンプルコード
「saveinstancestate」
public class AnotherActivity extends Activity {

private static final String KEY_TEXT = "key_text";



private String text;



public static Intent newIntent(Context context, String text) {

Intent intent = new Intent(context, AnotherActivity.class);

intent.putExtra(KEY_TEXT, text);

return intent;

}



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_another);



Intent intent = getIntent();

if (intent != null && intent.hasExtra(KEY_TEXT)) {

text = intent.getStringExtra(KEY_TEXT);

TextView textView = (TextView) findViewById(R.id.text);

textView.setText(text);

}

}

}
• 渡されたIntentの中身を取り出して次の
Activityのfieldに保存しておくことは良くある
と思うが、これをうっかり保存しわすれてその
フィールドがある前提でアクセスしてクラッ
シュ。誰もが初心者の時にやったことがある
のではないでしょうか。
onSaveInstanceState
強制ギプス
これで漏れを検知できる
初級編:非同期処理
Androidの非同期ライブラリ
• AsyncTask
• Loader
• Java’s Thread
• Handler (!)
• 3rd Party Libraries
• OkHttp
• Volley
• Retrofit
これらに共通して言えること
非同期処理はコントローラよ
り寿命が長いことがままある
public class MainActivity extends Activity {



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



new MyTask().execute();

}



private class MyTask extends AsyncTask<Void, Void, Void> {

@Override

protected Void doInBackground(Void... params) {

// heavy task
return null;

}



@Override

protected void onPostExecute(Void aVoid) {

// do something on Activity

}

}

}
サンプルコード
「asynctaskbadexample」
public class MainActivity extends Activity {



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



new MyTask().execute();

}



private class MyTask extends AsyncTask<Void, Void, Void> {

@Override

protected Void doInBackground(Void... params) {

// heavy task
return null;

}



@Override

protected void onPostExecute(Void aVoid) {

// do something on Activity

}

}

}
Activityより
長生きする可能性
がある
Activityより長生き…
ここにクラシュの罠がたくさんある
まずはAsyncTask
実はAsyncTaskは非推奨
(ワタシ的に)
• The dark side of AsyncTask
• http://bon-app-etit.blogspot.jp/2013/04/
the-dark-side-of-asynctask.html
• AsyncTask is bad and you should feel bad
• http://simonvt.net/2014/04/17/
asynctask-is-bad-and-you-should-feel-
bad/
• もともと長くて数秒の非同期処理にのみ使うことを推奨されてい
る
• 基本やりっ放しなので処理を丸々無駄にする
• cancel()すればいいのでは?
• BitmapFactory.decodeStream()みたいなキャンセルできない
操作もある
• バージョンによってシーケンシャルかパラレルかが異なる
• 画面回転等で結果を引き継げない
• onRetainNonConfigurationInstanceとか使えばいいけどそん
なことするぐらいなら後述のLoader使ったほうがいい
どうしてもAsyncTaskを
使いたい場合…
public class MainActivity extends Activity {

private static final String TAG = MainActivity.class.getSimpleName();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new MyTask(new MyTask.Callback() {

@Override

public void onFinish() {

Log.d(TAG, "finish");

}

}).execute();

}



private static class MyTask extends AsyncTask<Void, Void, Void> {

private Callback callback;



private MyTask(Callback callback) {

this.callback = callback;

}



@Override

protected Void doInBackground(Void... params) {

// do something

return null;

}



@Override

protected void onPostExecute(Void aVoid) {

callback.onFinish();

}



private interface Callback {

void onFinish();

}

}

}
ほんのちょっと
マシな例
サンプルコード
「asynctaskbetterexample」
もうほんのちょっ
とマシな例
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new MyTask(new MyTask.Callback() {

@Override

public void onFinish() {

Log.d(TAG, "finish");

}

}).execute();

}



private static class MyTask extends AsyncTask<Void, Void, Void> {

private WeakReference<Callback> callbackRef;



private MyTask(Callback callback) {

callbackRef = new WeakReference<Callback>(callback);

}



@Override

protected Void doInBackground(Void... params) {

// do something

return null;

}



@Override

protected void onPostExecute(Void aVoid) {

Callback callback = callbackRef.get();

if (callback != null)

callback.onFinish();

}



private interface Callback {

void onFinish();

}

}
サンプルコード
「asynctaskmorebetterexample」
private MyTask task;



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

task = new MyTask(new MyTask.Callback() {

@Override

public void onFinish() {

Log.d(TAG, "finish");

}

});

task.execute();

}



@Override

protected void onDestroy() {

super.onDestroy();

task.cancel(true);

}



private static class MyTask extends AsyncTask<Void, Void, Void> {

// 前略



@Override

protected Void doInBackground(Void... params) {

while (taskRemaining()) {

if (isCancelled()) {

Log.d(TAG, "canceled");

return null;

}

doHeavyTask();

}

return null;

}



// 後略

}
もうほんの
あと少しマシな例
サンプルコード
「asynctaskmuchmorebetterexample」
AsyncTaskはちょろっとした処
理をするのに便利なのも事実な
ので上手に付き合おう
AsyncTaskLoader
• ActivityやFragmentのライフサイクルと非同
期処理を切り離すことができる
• コールバックをコントローラ側に簡単に記述で
きる。結果はメインスレッドで受け取れる。
• 一番重要な点は、画面回転等でも非同期処理を
引き継げるような書き方が簡単にできること。
public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {

private static final String TAG = MainActivity.class.getSimpleName();



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

LoaderManager manager = getLoaderManager();

manager.initLoader(0, null, this);

}



@Override

public Loader<String> onCreateLoader(int id, Bundle args) {

return new MyLoader(this.getApplicationContext());

}



@Override

public void onLoadFinished(Loader<String> loader, String data) {

Log.d(TAG, data);

}



@Override

public void onLoaderReset(Loader<String> loader) {

// NOP

}
サンプルコード
「loadersimpleexample」
private static class MyLoader extends AsyncTaskLoader<String> {

private String mCachedData;



private MyLoader(Context context) {

super(context);

}



@Override

public String loadInBackground() {

return "fetched";

}



@Override

public void deliverResult(String data) {

if (isReset()) {

if (mCachedData != null) {

mCachedData = null;

}

return;

}

mCachedData = data;

if (isStarted()) {

super.deliverResult(data);

}

}



@Override

protected void onStartLoading() {

if (mCachedData != null) {

deliverResult(mCachedData);

return;

}



if (takeContentChanged() || mCachedData == null) {

forceLoad();

}

}



@Override

protected void onStopLoading() {

cancelLoad();

super.onStopLoading();

}



@Override

protected void onReset() {

onStopLoading();

super.onReset();

}

}

• Loaderを管理するLoaderManagerはActivityやFragment
ごとにひとつ。
• 画面回転でもLoaderManagerインスタンスは死なない。
• LoaderManager#initLoaderではコールバックをセットし
直しつつ処理を引き継ぐ。
• LoaderManager#restartLoaderでは既存の非同期処理を破
棄して新たに非同期処理を行う。
AsyncTaskとの最大の違い
• AsyncTaskの中にコールバックメソッドがある
• →利用側にコールバックのロジックを持つのが
手間
• AsyncTaskLoaderはLoaderCallbacksを利用側
が実装するので使いやすい
EventBus
• Observerパターンのような感じでライフサイクルオブジェクト
は自分のライフサイクルに合わせてイベントの購読/非購読する
• 非同期処理が終わったら購読者に完了イベントを一斉通知する
• コールバックが基本一対一なのに対し、一対多へ通知も可能。
• Loader同様、ライフサイクルオブジェクトより長命な処理が無
駄にならず、ライフサイクル側でregister/unregisterするので
コールバック時にライフサイクルが終わっている危険性も無い。
import com.squareup.otto.Bus;



public final class BusProvider {

private static final Bus BUS = new Bus();



public static Bus getInstance() {

return BUS;

}



private BusProvider() {

}

}
サンプルコード
「eventbusexample」
BusProvider.getInstance().post(new NewVersionAvailableEvent(latestVersion));
イベントを発火
@Override

protected void onResume() {

super.onResume();

BusProvider.getInstance().register(this);

}

@Override

protected void onPause() {

super.onPause();

BusProvider.getInstance().unregister(this);

}



@Subscribe

public void onEventReceived(HogeEvent event) {

}
• square/otto
• https://github.com/square/otto
• greenbot/EventBus
• https://github.com/greenrobot/EventBus
• おれおれコールバック設計
• http://qiita.com/hnakagawa/items/984557b13aede61d05d0
• EventBusとは違うけど非常に参考になる
RxJava/RxAndroid
RxJava/RxAndroid
• ここ一年で物凄い勢いで注目を集めているライブラリ及びプ
ログラミング手法
• Reactive Functional Programming
• LINQのような集合操作メソッド群と遅延評価を合わせたよう
な関数型的プログラミング手法
• コールバックヘルからの脱却!
• これだけで長大な記事になるので機会があれば後日記事にし
ます!!!(今回は泣く泣く断念)
Contextの正体を意識する
• Context…アプリケーションの様々な情報にアク
セスするためのインタフェース
• 画像、文字等の各種リソース
• アプリケーションそのものの情報
• パーミッション等々
概念が抽象的すぎてよくわからない
大きく分けて
ApplicationContext
ActivityContext
もうあと2つぐら
いあるらしいけど
なぜContextの正体を知って
いる必要があるか?
ActivityContextが長く参照さ
れる=深刻なメモリリーク
public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



new MyTask(getApplicationContext()).execute();

}



private class MyTask extends AsyncTask<Void, Void, Void> {

private Context context;



private MyTask(Context context) {

this.context = context;

}



@Override

protected Void doInBackground(Void... params) {

context.getString(R.string.hello_world);

return null;

}

}

}

だいたいのケースで
ApplicationContextが使える
じゃあ全部
ApplicationContext
でいいの?
• Activity 外から startActivity する場合は Intent
に FLAG_ACTIVITY_NEW_TASK が含まれている必要
がある。
• AlertDialog.BuilderにApplicationContextを渡すと
WindowTokenの取得に失敗
• Toast時に意図しないテーマが出たりすることも
new	
  AlertDialog.Builder(getApplicationContext());
E/AndroidRuntime: Caused by:
android.view.WindowManager$BadTokenException:
Unable to add window -- token null is not for an application
やはり、ちゃんと理解して気
持ちよく使おう!
原則:ActivityContextをActivity
より長命などこかに渡す場面に遭
遇したら、設計を見なおせ!
Fragmentあれこれ
Fragmentは気をつけないと非
常にクラッシュの元になります
原則その1:
Fragmentインスタンスにsetしない
Fragment fragment = new BlankFragment();

fragment.setParam(param);

getFragmentManager().beginTransaction()

.replace(android.R.id.content, fragment)

.commit();
——————————————————————————————————————————————————————
Fragment fragment = new BlankFragment(param1, param2);

getFragmentManager().beginTransaction()

.replace(android.R.id.content, fragment)

.commit();
どっちも
間違い!
public class BlankFragment extends Fragment {

private static final String ARG_PARAM1 = "param1";

private static final String ARG_PARAM2 = "param2";



private String mParam1;

private String mParam2;



public static BlankFragment newInstance(String param1, String param2) {

BlankFragment fragment = new BlankFragment();

Bundle args = new Bundle();

args.putString(ARG_PARAM1, param1);

args.putString(ARG_PARAM2, param2);

fragment.setArguments(args);

return fragment;

}



public BlankFragment() {

// Required empty public constructor

}



@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

if (getArguments() != null) {

mParam1 = getArguments().getString(ARG_PARAM1);

mParam2 = getArguments().getString(ARG_PARAM2);

}

}



@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

// Inflate the layout for this fragment

return inflater.inflate(R.layout.fragment_blank, container, false);

}
原則その2:リスナもsetできない
BlankFragment fragment = BlankFragment.newInstance("param1", "param2");

fragment.setListener(new BlankFragment.OnFragmentInteractionListener() {

@Override

public void onFragmentInteraction(Uri uri) {

// interaction

}

});



getFragmentManager().beginTransaction()

.replace(android.R.id.content, fragment)

.commit();
もちろん
間違い!
原則その3:リスナは
setSerializableで渡せない
public class BlankFragment extends Fragment {

private static final String ARG_PARAM1 = "param1";

private static final String ARG_PARAM2 = "param2";

private static final String ARG_LISTENER = "listener";



private String mParam1;

private String mParam2;

private OnFragmentInteractionListener mListener;



public static BlankFragment newInstance(String param1, String param2, OnFragmentInteractionListener listener) {

BlankFragment fragment = new BlankFragment();

Bundle args = new Bundle();

args.putString(ARG_PARAM1, param1);

args.putString(ARG_PARAM2, param2);

args.putSerializable(ARG_LISTENER, listener);

fragment.setArguments(args);

return fragment;

}



public BlankFragment() {

// Required empty public constructor

}



@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

if (getArguments() != null) {

mParam1 = getArguments().getString(ARG_PARAM1);

mParam2 = getArguments().getString(ARG_PARAM2);

mListener = (OnFragmentInteractionListener) getArguments().getSerializable(ARG_LISTENER);

}

}
public interface OnFragmentInteractionListener extends Serializable {

public void onFragmentInteraction(Uri uri);

}
一見行けそうだが
…
@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);



BlankFragment fragment = BlankFragment.newInstance("param1", "param2", new BlankFragment.OnFragmentInteractionListener() {

@Override

public void onFragmentInteraction(Uri uri) {

// interaction

}

});



getFragmentManager().beginTransaction()

.replace(android.R.id.content, fragment)

.commit();

}
Activityへの
暗黙の参照
• https://docs.oracle.com/javase/jp/1.4/guide/serialization/spec/serial-
arch.doc10.html
• (引用)ローカルクラスおよび匿名クラスを含む内部クラス (static メンバクラスでは
ない入れ子のクラス) の直列化は、いくつかの理由により、使用しないことを強くお勧
めします。非 static コンテキストで宣言された内部クラスには、囲むクラスインスタン
スへの暗黙的な非 transient 参照が含まれるので、そのような内部クラスインスタンス
を直列化すると、関連する外部クラスインスタンスも直列化されることになります。内
部クラスを実装する javac (またはその他の JavaTM コンパイラ) によって生成された
合成フィールドは、実装に依存するので、コンパイラによって相違が生じることがあり
ます。
@Override

public void onAttach(Activity activity) {

super.onAttach(activity);

try {

mListener = (OnFragmentInteractionListener) activity;

} catch (ClassCastException e) {

throw new ClassCastException(activity.toString()

+ " must implement OnFragmentInteractionListener");

}

}
Activityで
implement
サンプルコードの
「fragmentexample」
EventBusはActivity-Fragmentの
インタラクションにも有効
FragmentTransactionに
ご用心!
BlankFragment fragment = BlankFragment.newInstance("param1", "param2");

fragment.setListener(new BlankFragment.OnFragmentInteractionListener() {

@Override

public void onFragmentInteraction(Uri uri) {

// interaction

}

});



getFragmentManager().beginTransaction()

.replace(android.R.id.content, fragment)

.commit();
• onSaveInstanceState以降にFragmentTransactionを伴う処理を行うと
IllegalStateExceptionが発生する
• これは、そのタイミング以降になにか変更をしても、もしインスタンスが再
生成された場合に元の状態に戻しようがないため
• FragmentTransaction.commitAllowingStateLoss()すれば例外が上がらな
いようにはできる
• 意外な盲点として、DialogFragment#show, dissmissはFragmentTransaction
を伴う処理であるということ。
• 非同期通信の間何かダイアログを出し、完了後にdissmissするような処理は非
常にありがちなので、タイミング次第で発生するクラッシュになる。
• 弊社のクラッシュでもFragmentTransactionに起因する例外が非常に多かっ
た!
Fragment#isResumed()
isベンリ
if (isResumed()) {

dialog.dismiss();

}


public class BaseActivity extends Activity {

private volatile boolean mIsResumed = false;



@Override

protected void onResume() {

super.onResume();

mIsResumed = true;

}



@Override

protected void onPause() {

super.onPause();

mIsResumed = false;

}



protected boolean isActivityResumed() {

return mIsResumed;

}



protected boolean isActivityPaused() {

return !mIsResumed;

}



}

Activity版を作る
と気休めになる
onResume/onPause間で
安全にFragmentTransactionする
テクニック紹介
public abstract class PauseHandler<T> extends Handler {

private final List<Message> messageQueueBuffer = Collections.synchronizedList(new ArrayList<Message>());



private T obj;

public final synchronized void resume(T obj) {

this.obj = obj;



while (messageQueueBuffer.size() > 0) {

final Message msg = messageQueueBuffer.get(0);

messageQueueBuffer.remove(0);

sendMessage(msg);

}

}



public final synchronized void pause() {

obj = null;

}



@Override

public final synchronized void handleMessage(Message msg) {

if (obj == null) {

final Message msgCopy = new Message();

msgCopy.copyFrom(msg);

messageQueueBuffer.add(msgCopy);

} else {

processMessage(obj, msg);

}

}



protected abstract void processMessage(T obj, Message message);



}
サンプルコードの
「pausehandler」
private static class ActivityPauseHandler extends PauseHandler<BaseActivity> {

@Override

protected void processMessage(BaseActivity activity, Message message) {

activity.processMessage(message);

}

}
public ActivityPauseHandler mPauseHandler = new ActivityPauseHandler();
@Override

protected void onResume() {

super.onResume();

mPauseHandler.resume(this);

}
@Override

protected void onPause() {

super.onPause();

mPauseHandler.pause();

}
@Override

public void processMessage(Message message) {

if (message.what != WHAT_SHOW_DIALOG) {

return;

}
dialog.show(getSupportFragmentManager(), "TAG");

}
Handlerを理解する
Handlerとはなにか
mHandler.post(new Runnable() {

@Override

public void run() {

Toast.makeText(context, text, Toast.LENGTH_SHORT).show();



}

});
ワーカスレッドか
ら呼び出し
ワーカスレッドからUIスレッドを
触るときに使う不思議なやつ…?
だけではないんです。
• 任意のThread(メッセージループ)にメッセージを送ったりメッ
セージを取り出して処理したりする人
• AndroidではLooperがメッセージループ
• Messageがメッセージ(そのまま!)
• LooperはMessageを貯めておいて随時実行するキューを持ってい
る(MessageQueue)
• 単純なキューではない。遅延実行等を加味されてキューに積まれる。
なぜこれを知っておく必要があるか?
AndroidのUI
=シングルスレッドモデル
UI更新はUIスレッドのメッセージ
キューに積んで処理してもらう必要
がある。
new Handler()された場所のThreadに紐づく=UIス
レッドでnewされたらUIスレッドにメッセージが送れ
るというだけ!
あるいは
new Handler(Looper.getMainLooper());
AndroidではUIスレッド以外でUI操
作を試みた時点でクラッシュする
いままでなんとなくHandler使っ
てませんでしたか?
Handlerとその奥に流れる思想を理解で
きたらいよいよAndroid中級者です!
Handlerの応用例
HandlerThread thread = new HandlerThread(NON_UI_HANDLER_THREAD_NAME);

thread.start();

mNonUiHandler = new Handler(thread.getLooper());
Canvas canvas = mHolder.lockCanvas();

canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC);

canvas.concat(mMatrix);

drawImages(canvas);

canvas.restoreToCount(saveCount);

mHolder.unlockCanvasAndPost(canvas);
静的解析のチカラを借りる
Javaはよくも悪くも強い静的型付
け言語である。
型、アノテーション、いずれも強
力なのだから最大限利用すべき
@Nullable
@NonNull
nullチェックがないと警告
nullを渡すと警告
@BooleanRes
@ColorStateListRes
@DrawableRes
@IntArrayRes
@IntegerRes
@LayoutRes
@MovieRes
@TextRes
@TextArrayRes
@StringArrayRes
https://github.com/excilys/
androidannotations/wiki/Resources
int型でも、対応するリソースの
intでないとコンパイルエラー
private ConfabDetailState(int statusId, @StringRes int
statusStringId, @StringRes int tutorLabelId, @ColorRes int
borderColorId, @ColorRes int backgroundColorId) {

mStatusId = statusId;

mStatusStringId = statusStringId;

mTutorLabelId = tutorLabelId;

mBorderColorId = borderColorId;

mBackgroundColorId = backgroundColorId;

}
意図しないintの代入を
コンパイル時に防げる
絶対に落ちないアプリが
本当に幸せか?
• ゼロ除算の発生しうる場所だったの
でガチガチのチェックをしてクラッ
シュすることがないように初期値を
入れたりしたが、実はAPIのバグ以
外で0が返ることはありえない場所
• かえってAPIの不具合の発見を遅ら
せる結果になった
落ちるときは素直に落ちるのも手
お聞きいただきありがとうございました。
We're Hiring!
• 教育で世界を変える仲間を募集しています!
• iOS技術者
• Android技術者
• http://mana.bo/corp/recruit/

Más contenido relacionado

La actualidad más candente

PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門泰 増田
 
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -onozaty
 
FastAPIのテンプレートプロジェクトがいい感じだった話
FastAPIのテンプレートプロジェクトがいい感じだった話FastAPIのテンプレートプロジェクトがいい感じだった話
FastAPIのテンプレートプロジェクトがいい感じだった話NipponAlgorithm
 
知らないと損するアプリ開発におけるStateMachineの活用法(full版)
知らないと損するアプリ開発におけるStateMachineの活用法(full版)知らないと損するアプリ開発におけるStateMachineの活用法(full版)
知らないと損するアプリ開発におけるStateMachineの活用法(full版)Ken Morishita
 
WebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話すWebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話すTakaya Saeki
 
webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話
webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話
webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話Yuhei Miyazato
 
C#メタプログラミング概略 in 2021
C#メタプログラミング概略 in 2021C#メタプログラミング概略 in 2021
C#メタプログラミング概略 in 2021Atsushi Nakamura
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線MeetupMasatoshi Tada
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...Philip Schwarz
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 TipsTakaaki Suzuki
 
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST APIRedmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST APIGo Maeda
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎信之 岩永
 
RESTful Web アプリの設計レビューの話
RESTful Web アプリの設計レビューの話RESTful Web アプリの設計レビューの話
RESTful Web アプリの設計レビューの話Takuto Wada
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについてkumake
 
HTTP2 最速実装 〜入門編〜
HTTP2 最速実装 〜入門編〜HTTP2 最速実装 〜入門編〜
HTTP2 最速実装 〜入門編〜Kaoru Maeda
 
100%Kotlin ORM Ktormを試してみた
100%Kotlin ORM Ktormを試してみた100%Kotlin ORM Ktormを試してみた
100%Kotlin ORM Ktormを試してみたKeita Tsukamoto
 
Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Scott Wlaschin
 
ジェネリクスの基礎と クラス設計への応用
ジェネリクスの基礎とクラス設計への応用ジェネリクスの基礎とクラス設計への応用
ジェネリクスの基礎と クラス設計への応用nagise
 
AppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころAppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころMasayuki Wakizaka
 
hooks riverpod + state notifier + freezed でのドメイン駆動設計
hooks riverpod + state notifier + freezed でのドメイン駆動設計hooks riverpod + state notifier + freezed でのドメイン駆動設計
hooks riverpod + state notifier + freezed でのドメイン駆動設計Shinnosuke Tokuda
 

La actualidad más candente (20)

PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門PlaySQLAlchemy: SQLAlchemy入門
PlaySQLAlchemy: SQLAlchemy入門
 
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
 
FastAPIのテンプレートプロジェクトがいい感じだった話
FastAPIのテンプレートプロジェクトがいい感じだった話FastAPIのテンプレートプロジェクトがいい感じだった話
FastAPIのテンプレートプロジェクトがいい感じだった話
 
知らないと損するアプリ開発におけるStateMachineの活用法(full版)
知らないと損するアプリ開発におけるStateMachineの活用法(full版)知らないと損するアプリ開発におけるStateMachineの活用法(full版)
知らないと損するアプリ開発におけるStateMachineの活用法(full版)
 
WebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話すWebAssemblyのWeb以外のことぜんぶ話す
WebAssemblyのWeb以外のことぜんぶ話す
 
webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話
webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話
webSocket通信を知らないiOSエンジニアが知っておいて損はしない(経験談的な)軽い話
 
C#メタプログラミング概略 in 2021
C#メタプログラミング概略 in 2021C#メタプログラミング概略 in 2021
C#メタプログラミング概略 in 2021
 
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetupこれで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
これで怖くない!?コードリーディングで学ぶSpring Security #中央線Meetup
 
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...Sum and Product Types -The Fruit Salad & Fruit Snack Example - From F# to Ha...
Sum and Product Types - The Fruit Salad & Fruit Snack Example - From F# to Ha...
 
今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips今日からできる!簡単 .NET 高速化 Tips
今日からできる!簡単 .NET 高速化 Tips
 
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST APIRedmineをちょっと便利に! プログラミング無しで使ってみるREST API
Redmineをちょっと便利に! プログラミング無しで使ってみるREST API
 
非同期処理の基礎
非同期処理の基礎非同期処理の基礎
非同期処理の基礎
 
RESTful Web アプリの設計レビューの話
RESTful Web アプリの設計レビューの話RESTful Web アプリの設計レビューの話
RESTful Web アプリの設計レビューの話
 
日本語テストメソッドについて
日本語テストメソッドについて日本語テストメソッドについて
日本語テストメソッドについて
 
HTTP2 最速実装 〜入門編〜
HTTP2 最速実装 〜入門編〜HTTP2 最速実装 〜入門編〜
HTTP2 最速実装 〜入門編〜
 
100%Kotlin ORM Ktormを試してみた
100%Kotlin ORM Ktormを試してみた100%Kotlin ORM Ktormを試してみた
100%Kotlin ORM Ktormを試してみた
 
Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)Domain Modeling Made Functional (DevTernity 2022)
Domain Modeling Made Functional (DevTernity 2022)
 
ジェネリクスの基礎と クラス設計への応用
ジェネリクスの基礎とクラス設計への応用ジェネリクスの基礎とクラス設計への応用
ジェネリクスの基礎と クラス設計への応用
 
AppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころAppiumのWebViewアプリテストの仕組みとハマりどころ
AppiumのWebViewアプリテストの仕組みとハマりどころ
 
hooks riverpod + state notifier + freezed でのドメイン駆動設計
hooks riverpod + state notifier + freezed でのドメイン駆動設計hooks riverpod + state notifier + freezed でのドメイン駆動設計
hooks riverpod + state notifier + freezed でのドメイン駆動設計
 

Destacado

JobStreamerではじめるJavaBatchのクラウド分散実行
JobStreamerではじめるJavaBatchのクラウド分散実行JobStreamerではじめるJavaBatchのクラウド分散実行
JobStreamerではじめるJavaBatchのクラウド分散実行Yoshitaka Kawashima
 
開発を効率的に進めるられるまでの道程
開発を効率的に進めるられるまでの道程開発を効率的に進めるられるまでの道程
開発を効率的に進めるられるまでの道程Takao Sumitomo
 
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
出来るチューリング完全!SQLでもいろいろ出来る! #syobobenkyon mm
 
Droid kaigiプレゼン
Droid kaigiプレゼンDroid kaigiプレゼン
Droid kaigiプレゼンSuguru Oho
 
データモデルは時空を越える
データモデルは時空を越えるデータモデルは時空を越える
データモデルは時空を越えるterahide
 
Android学ぶを君へ。生き抜くためのナレッジ共有
Android学ぶを君へ。生き抜くためのナレッジ共有Android学ぶを君へ。生き抜くためのナレッジ共有
Android学ぶを君へ。生き抜くためのナレッジ共有Shinobu Okano
 
プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例sohta
 
Java web application testing
Java web application testingJava web application testing
Java web application testingTokuhiro Matsuno
 
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情についてあなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情についてShinichi Kozake
 
DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素Takahiro YAMADA
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)Yoshitaka Kawashima
 
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -Yuki Anzai
 
マテリアルデザインを用いたデザインリニューアル [フリル編]
マテリアルデザインを用いたデザインリニューアル [フリル編]マテリアルデザインを用いたデザインリニューアル [フリル編]
マテリアルデザインを用いたデザインリニューアル [フリル編]YUKI YAMAGUCHI
 
Asian Automation Alliance 自動化を進める・止めるにあたってのヒント
Asian Automation Alliance 自動化を進める・止めるにあたってのヒントAsian Automation Alliance 自動化を進める・止めるにあたってのヒント
Asian Automation Alliance 自動化を進める・止めるにあたってのヒントTakahiro Toku
 
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃんRetrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃんYukari Sakurai
 
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]bitter_fox
 

Destacado (16)

JobStreamerではじめるJavaBatchのクラウド分散実行
JobStreamerではじめるJavaBatchのクラウド分散実行JobStreamerではじめるJavaBatchのクラウド分散実行
JobStreamerではじめるJavaBatchのクラウド分散実行
 
開発を効率的に進めるられるまでの道程
開発を効率的に進めるられるまでの道程開発を効率的に進めるられるまでの道程
開発を効率的に進めるられるまでの道程
 
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
出来るチューリング完全!SQLでもいろいろ出来る! #syoboben
 
Droid kaigiプレゼン
Droid kaigiプレゼンDroid kaigiプレゼン
Droid kaigiプレゼン
 
データモデルは時空を越える
データモデルは時空を越えるデータモデルは時空を越える
データモデルは時空を越える
 
Android学ぶを君へ。生き抜くためのナレッジ共有
Android学ぶを君へ。生き抜くためのナレッジ共有Android学ぶを君へ。生き抜くためのナレッジ共有
Android学ぶを君へ。生き抜くためのナレッジ共有
 
プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例プログラミング言語Clojureのニャンパスでの活用事例
プログラミング言語Clojureのニャンパスでの活用事例
 
Java web application testing
Java web application testingJava web application testing
Java web application testing
 
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情についてあなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
あなたとAndroid 今すぐダウンロード!? Android開発で変わる SIerのJava技術事情について
 
DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素DB設計でこだわりたい三つの要素
DB設計でこだわりたい三つの要素
 
イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)イミュータブルデータモデル(世代編)
イミュータブルデータモデル(世代編)
 
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
Activity, Fragment, CustomView の使い分け - マッチョなActivityにさよならする方法 -
 
マテリアルデザインを用いたデザインリニューアル [フリル編]
マテリアルデザインを用いたデザインリニューアル [フリル編]マテリアルデザインを用いたデザインリニューアル [フリル編]
マテリアルデザインを用いたデザインリニューアル [フリル編]
 
Asian Automation Alliance 自動化を進める・止めるにあたってのヒント
Asian Automation Alliance 自動化を進める・止めるにあたってのヒントAsian Automation Alliance 自動化を進める・止めるにあたってのヒント
Asian Automation Alliance 自動化を進める・止めるにあたってのヒント
 
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃんRetrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
Retrofit2 &OkHttp 
でAndroidのHTTP通信が快適だにゃん
 
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
徹底解説!Project Lambdaのすべて[JJUG CCC 2013 Fall H-2]
 

Similar a 絶対落ちないアプリの作り方

ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用Yatabe Terumasa
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDEdcubeio
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)Iwana Chan
 
Async Enhancement
Async EnhancementAsync Enhancement
Async Enhancementkamiyam .
 
15分でCakePHPを始める方法(Nseg 2013-11-09 )
15分でCakePHPを始める方法(Nseg 2013-11-09 )15分でCakePHPを始める方法(Nseg 2013-11-09 )
15分でCakePHPを始める方法(Nseg 2013-11-09 )hiro345
 
AWS SDK for Smalltalk
AWS SDK for SmalltalkAWS SDK for Smalltalk
AWS SDK for SmalltalkSho Yoshida
 
Inside frogc in Dart
Inside frogc in DartInside frogc in Dart
Inside frogc in DartGoro Fuji
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」yoshiaki iwanaga
 
laravel x モバイルアプリ
laravel x モバイルアプリlaravel x モバイルアプリ
laravel x モバイルアプリMasaki Oshikawa
 
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションPlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションKazuhiro Hara
 
Scalaでプログラムを作りました
Scalaでプログラムを作りましたScalaでプログラムを作りました
Scalaでプログラムを作りましたTomoharu ASAMI
 
Tokyo GTUG Bootcamp2010
Tokyo GTUG Bootcamp2010Tokyo GTUG Bootcamp2010
Tokyo GTUG Bootcamp2010Takashi EGAWA
 
GroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackGroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackTakahiro Yoshimura
 
omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜Sotaro Omura
 
20130924 Picomon CRH勉強会
20130924 Picomon CRH勉強会20130924 Picomon CRH勉強会
20130924 Picomon CRH勉強会Yukihiro Kitazawa
 
Application Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD PatternApplication Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD PatternAtsushi Kambara
 
マイクロサービス時代の生存戦略 with HashiCorp
マイクロサービス時代の生存戦略 with HashiCorpマイクロサービス時代の生存戦略 with HashiCorp
マイクロサービス時代の生存戦略 with HashiCorpMasahito Zembutsu
 
20170422 azure portal cli 使いこなし
20170422 azure portal cli 使いこなし20170422 azure portal cli 使いこなし
20170422 azure portal cli 使いこなしTakayoshi Tanaka
 

Similar a 絶対落ちないアプリの作り方 (20)

ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用ソーシャルアプリ勉強会(第一回資料)配布用
ソーシャルアプリ勉強会(第一回資料)配布用
 
React Native GUIDE
React Native GUIDEReact Native GUIDE
React Native GUIDE
 
Rx java x retrofit
Rx java x retrofitRx java x retrofit
Rx java x retrofit
 
社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)社内勉強会資料(Varnish Module)
社内勉強会資料(Varnish Module)
 
Async Enhancement
Async EnhancementAsync Enhancement
Async Enhancement
 
AndroidでDIxAOP
AndroidでDIxAOPAndroidでDIxAOP
AndroidでDIxAOP
 
15分でCakePHPを始める方法(Nseg 2013-11-09 )
15分でCakePHPを始める方法(Nseg 2013-11-09 )15分でCakePHPを始める方法(Nseg 2013-11-09 )
15分でCakePHPを始める方法(Nseg 2013-11-09 )
 
AWS SDK for Smalltalk
AWS SDK for SmalltalkAWS SDK for Smalltalk
AWS SDK for Smalltalk
 
Inside frogc in Dart
Inside frogc in DartInside frogc in Dart
Inside frogc in Dart
 
第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」第三回ありえる社内勉強会 「いわががのLombok」
第三回ありえる社内勉強会 「いわががのLombok」
 
laravel x モバイルアプリ
laravel x モバイルアプリlaravel x モバイルアプリ
laravel x モバイルアプリ
 
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC WebアプリケーションPlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
PlayFramework 2.0 Javaと WebSocketでつくる リアルタイムMVC Webアプリケーション
 
Scalaでプログラムを作りました
Scalaでプログラムを作りましたScalaでプログラムを作りました
Scalaでプログラムを作りました
 
Tokyo GTUG Bootcamp2010
Tokyo GTUG Bootcamp2010Tokyo GTUG Bootcamp2010
Tokyo GTUG Bootcamp2010
 
GroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hackGroovyなAndroidテスト #atest_hack
GroovyなAndroidテスト #atest_hack
 
omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜omoon.org の裏側 〜FuelPHP の task 活用例〜
omoon.org の裏側 〜FuelPHP の task 活用例〜
 
20130924 Picomon CRH勉強会
20130924 Picomon CRH勉強会20130924 Picomon CRH勉強会
20130924 Picomon CRH勉強会
 
Application Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD PatternApplication Architecture for Enterprise Win Store Apps with DDD Pattern
Application Architecture for Enterprise Win Store Apps with DDD Pattern
 
マイクロサービス時代の生存戦略 with HashiCorp
マイクロサービス時代の生存戦略 with HashiCorpマイクロサービス時代の生存戦略 with HashiCorp
マイクロサービス時代の生存戦略 with HashiCorp
 
20170422 azure portal cli 使いこなし
20170422 azure portal cli 使いこなし20170422 azure portal cli 使いこなし
20170422 azure portal cli 使いこなし
 

Más de Fumihiko Shiroyama

GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例Fumihiko Shiroyama
 
GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発Fumihiko Shiroyama
 
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFirebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFumihiko Shiroyama
 
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしようRxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしようFumihiko Shiroyama
 
Ops worksに今後期待するところ
Ops worksに今後期待するところOps worksに今後期待するところ
Ops worksに今後期待するところFumihiko Shiroyama
 

Más de Fumihiko Shiroyama (10)

Firebase with Android
Firebase with AndroidFirebase with Android
Firebase with Android
 
RxJava - Subject 入門
RxJava - Subject 入門RxJava - Subject 入門
RxJava - Subject 入門
 
GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例GCP HTTPロードバランサ運用例
GCP HTTPロードバランサ運用例
 
GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発GDG Tokyo Firebaseを使った Androidアプリ開発
GDG Tokyo Firebaseを使った Androidアプリ開発
 
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリFirebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
Firebaseで驚くほど簡単に作れるリアルタイムイベントドリブンアプリ
 
AndroidでEither
AndroidでEitherAndroidでEither
AndroidでEither
 
Rxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしようRxjavaとoptionalで関数型androidしよう
Rxjavaとoptionalで関数型androidしよう
 
Ops worksに今後期待するところ
Ops worksに今後期待するところOps worksに今後期待するところ
Ops worksに今後期待するところ
 
Wallet api
Wallet apiWallet api
Wallet api
 
Google io 2013_keynote
Google io 2013_keynoteGoogle io 2013_keynote
Google io 2013_keynote
 

絶対落ちないアプリの作り方