Upgrade to Pro — share decks privately, control downloads, hide ads and more …

4年続くアプリにおけるチーム開発 #DroidKaigi 2017

4年続くアプリにおけるチーム開発 #DroidKaigi 2017

2017/3/10
#DroidKaigi 2017 でお話した「フリル」のチーム開発に関する資料です

Tatsuya Arai

March 10, 2017
Tweet

More Decks by Tatsuya Arai

Other Decks in Technology

Transcript

  1. • v1.0 • v2.1 • ެࣜγϣοϓػೳ௥Ճ • v2.3 • ActionBarԽ

    • σβΠϯϦχϡʔΞϧ • v2.5 • FrilAPIClient΁ͷҠߦ • v3.0 • UIϦχϡʔΞϧ • v3.6 • ͓͢͢ΊϢʔβʔϦ χϡʔΞϧ • v4.0 • UIϦχϡʔΞϧ • v4.1.2 • RxAndroid1.0ʹߋ৽ • v4.3 • Android WearΞϓϦ ͷ௥Ճ • v5.0 • ৭ݕࡧػೳͷ௥Ճ • v5.2 • ͕͢͞ը໘ϦχϡʔΞ ϧ • v5.3.2 • νϟοταϙʔτ • v5.5.0 • FCM΁ͷҠߦ • v5.7.0 • λΠϜϥΠϯɾ͕͢͞ ը໘ϦχϡʔΞϧ • v6.0 • v6.0.0 BIϦχϡʔΞ ϧɾϒϥϯυ&ੑผબ ୒ഇࢭ • v6.4 • SMSೝূ
  2. • v1.0 • v2.1 • ެࣜγϣοϓػೳ௥Ճ • v2.3 • ActionBarԽ

    • σβΠϯϦχϡʔΞϧ • v2.5 • FrilAPIClient΁ͷҠߦ • v3.0 • UIϦχϡʔΞϧ • v3.6 • ͓͢͢ΊϢʔβʔϦ χϡʔΞϧ • v4.0 • UIϦχϡʔΞϧ • v4.1.2 • RxAndroid1.0ʹߋ৽ • v4.3 • Android WearΞϓϦ ͷ௥Ճ • v5.0 • ৭ݕࡧػೳͷ௥Ճ • v5.2 • ͕͢͞ը໘ϦχϡʔΞ ϧ • v5.3.2 • νϟοταϙʔτ • v5.5.0 • FCM΁ͷҠߦ • v5.7.0 • λΠϜϥΠϯɾ͕͢͞ ը໘ϦχϡʔΞϧ • v6.0 • BIϦχϡʔΞϧɾϒϥ ϯυ&ੑผબ୒ഇࢭ • v6.4 • SMSೝূ
  3. v1.0~v1.1 public Loader<JSONObject> onCreateLoader(int index, Bundle args) { HashMap<String, String>

    params = new HashMap<String, String>(); params.put("method", "0"); params.put("grid_flag", "0"); params.put("pos", "0"); Loader<JSONObject> loader = new JSONLoader(this, "POST", “/timeline", params); loader.forceLoad(); return loader; } @Override public void onLoadFinished(Loader<JSONObject> arg0, JSONObject response) { if (response == null) return; mAdapter.loadFromJSON(response); if (mAdapter.getCount() > 0) { mListView.setAdapter(mAdapter); mListView.invalidate(); } } AsyncTaskLoader APIίʔϧ APIϨεϙϯε
  4. public RequestHandle getItemDetail(int itemId, final SingleModelCallback<ItemDetail> callback) {
 RequestParams params

    = new RequestParams(baseParams);
 params.put("item_id", String.valueOf(itemId));
 
 return httpClient.get(baseUrl + "/api/item", params, new JsonHttpResponseHandler() {
 @Override
 public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
 ItemDetail itemDetail = gson.fromJson(response.toString(), ItemDetail.class);
 callback.success(itemDetail);
 }
 
 @Override
 public void onFailure(int statusCode, Throwable e, JSONObject errorResponse) {
 callback.failure(statusCode, e, errorResponse);
 }
 });
 } android-async-http v2.0~
  5. private void getItemDetail() { apiClient.getItemDetail(mItem.getId(),new FrilAPIClient.SingleModelCallback<ItemDetail>() { @Override public void

    success(ItemDetail itemDetail) { setDetailView(itemDetail); } @Override public void failure(int statusCode, Throwable error, JSONObject errorResponse) { // Τϥʔॲཧ } }); } android-async-http v2.0~
  6. Observable<ItemDetail> observable = FrilServiceCreator.createFrilService(activity).getItemDetail(itemId);
 return observable.subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(new Action1<ItemDetail>() {


    @Override
 public void call(ItemDetail itemDetail) { setItemDetail(itemDetail);
 }
 }, new Action1<Throwable>() {
 @Override
 public void call(Throwable throwable) {
 Timber.e(throwable, throwable.getMessage());
 }
 }); Retrofit + RxJava v3.5~ @GET("/api/item")
 Observable<ItemDetail> getItemDetail(
 @Query("item_id") Integer itemId
 );
  7. ΞʔΩςΫνϟͷมભ    ωοτϫʔΫ "TZOD5BTL-PBEFS BOESPJE BTZODIUUQ 3FUSPpU ඇಉظॲཧ

    ΠϯλϑΣʔε -PBEFS $BMMCBDL 3Y+BWB &WFOU#VT TUBSU"DUJWJUZ'PS3FTVMU 0UUP 0UUP ը૾ 63-$POOFDUJPO 1JDBTTP 1JDBTTP
  8. RxJavaಋೖલ public class MigrateMasterDataTask extends AsyncTask<Void, Void, Boolean> { @Override


    protected Boolean doInBackground(Void... params) { final FrilService frilService = FrilServiceCreator.createFrilService(context);
 
 //ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ͔νΣοΫ
 Call<DatabaseUpdate> call = frilService.checkNeedDatabaseUpdateSync(
 AppPrefs.getBrandVersion(context),
 AppPrefs.getBankVersion(context));
 
 DatabaseUpdate databaseUpdate = call.execute().body();
 if (databaseUpdate == null) {
 return false;
 }
 
 // ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ
 boolean updateBrand = databaseUpdate.isNeedForBrand();
 boolean updateBank = databaseUpdate.isNeedForBank();
 
 if (!updateBrand && !updateBank) {
 return true;
 }
 
 //ϦϞʔτͷσʔλΛ SQLite ʹҠߦ
 return syncFromRemote(updateBrand, updateBank); } }
  9. RxJavaಋೖલ public class MigrateMasterDataTask extends AsyncTask<Void, Void, Boolean> { @Override


    protected Boolean doInBackground(Void... params) { final FrilService frilService = FrilServiceCreator.createFrilService(context);
 
 //ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ͔νΣοΫ
 Call<DatabaseUpdate> call = frilService.checkNeedDatabaseUpdateSync(
 AppPrefs.getBrandVersion(context),
 AppPrefs.getBankVersion(context));
 
 DatabaseUpdate databaseUpdate = call.execute().body();
 if (databaseUpdate == null) {
 return false;
 }
 
 // ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ
 boolean updateBrand = databaseUpdate.isNeedForBrand();
 boolean updateBank = databaseUpdate.isNeedForBank();
 
 if (!updateBrand && !updateBank) {
 return true;
 }
 
 //ϦϞʔτͷσʔλΛ SQLite ʹҠߦ
 return syncFromRemote(updateBrand, updateBank); } }
  10. RxJavaಋೖલ public class MigrateMasterDataTask extends AsyncTask<Void, Void, Boolean> { @Override


    protected Boolean doInBackground(Void... params) { final FrilService frilService = FrilServiceCreator.createFrilService(context);
 
 //ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ͔νΣοΫ
 Call<DatabaseUpdate> call = frilService.checkNeedDatabaseUpdateSync(
 AppPrefs.getBrandVersion(context),
 AppPrefs.getBankVersion(context));
 
 DatabaseUpdate databaseUpdate = call.execute().body();
 if (databaseUpdate == null) {
 return false;
 }
 
 // ϦϞʔτ͔ΒͷऔΓࠐΈ͕ඞཁ
 boolean updateBrand = databaseUpdate.isNeedForBrand();
 boolean updateBank = databaseUpdate.isNeedForBank();
 
 if (!updateBrand && !updateBank) {
 return true;
 }
 
 //ϦϞʔτͷσʔλΛ SQLite ʹҠߦ
 return syncFromRemote(updateBrand, updateBank); } }
  11. RxJavaಋೖલ private boolean syncFromRemote(boolean isNeedUpdateBrand, boolean isNeedUpdateBank) { if (isNeedUpdateBrand)

    { // ωοτϫʔΫ͔ΒϒϥϯυϚελΛಉظऔಘ } if (isNeedUpdateBank) { // ωοτϫʔΫ͔ΒۜߦϚελΛಉظऔಘ } if (brandVersion != null) { // ΞϓϦ಺ʹ࠷৽ͷόʔδϣϯ৘ใΛอଘ } if (bankVersion != null) { // ΞϓϦ಺ʹ࠷৽ͷόʔδϣϯ৘ใΛอଘ } return true; }
  12. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  13. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  14. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  15. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  16. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  17. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  18. RxJavaಋೖޙ public Completable migrateMasterData() {
 final String brandVersion = AppPrefs.getBrandVersion(context);


    final String bankVersion = AppPrefs.getBankVersion(context);
 return frilService.checkDatabaseUpdateNeeded(brandVersion, bankVersion)
 .flatMap(update -> {
 List<Completable> completables = new ArrayList<>();
 if (update.isNeedForBrand()) {
 completables.add(migrateBrandsFromRemote().subscribeOn(Schedulers.io()));
 }
 if (update.isNeedForBank()) {
 completables.add(migrateBanksFromRemote().subscribeOn(Schedulers.io()));
 }
 return Completable.merge(completables).toObservable();
 })
 .onErrorResumeNext(throwable -> {
 return Observable.error(throwable);
 })
 .toCompletable();
 } Subscription subscription = helper.migrateMasterData()
 .subscribeOn(Schedulers.io())
 .observeOn(AndroidSchedulers.mainThread())
 .subscribe(this::dismissProgressDialog, throwable -> {
 Timber.e(throwable, throwable.getMessage());
 });
 subscriptions.add(subscription);
  19. CI

  20. ໨తผνʔϜ B A ♂♂♂♂ ♂ ♂♂♂ ♂ ♂ ♂♂♂♂ ♂

    ♂♂♂ ♂ ♂♂♂ ♂♂ iOS Android Server Design
  21.