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

Android開発における、レガシーコードと戦うためのリファクタリング

 Android開発における、レガシーコードと戦うためのリファクタリング

2015/8/20 マネーフォワード×Eight -モバイルアプリ勉強会
Android開発におけるリファクタリングの実際を紹介します。

Jumpei Yamamoto

August 20, 2015
Tweet

More Decks by Jumpei Yamamoto

Other Decks in Programming

Transcript

  1. public void onLoadFinished(Integer result) {
 switch (result) {
 case 10:


    showErrorAlertDialog();
 break;
 case 11:
 showErrorAlertDialog();
 break;
 case 12:
 showErrorAlertDialog();
 break;
 case 20:
 case 30:
 case 31:
 showErrorAlertDialog();
 break;
 case 32:
 showErrorAlertDialog();
 break;
 case 1:
 break;
 }
 }
 何をあらわすのか   わかりません!! 問題点
  2. public enum FirstMyCardEntryStatus {
 /// ໊ࢗը૾౤ߘཁٻʢະ౤ߘঢ়ଶʣ
 BEFORE_UPLOAD(10),
 /// ໊ࢗը૾࠶౤ߘཁٻʢະ౤ߘঢ়ଶʣ
 REQUEST_REUPLOAD(11),


    /// αϜωΠϧԽલঢ়ଶ
 BEFORE_THUMBNAIL(20),
 /// ໊ࢗը૾ΤϯτϦૹ৴લ(໊ࢗը૾ΤϯτϦొ࿥લ)
 BEFORE_SEND_ENTRY(30),
 /// ໊ࢗը૾ΤϯτϦૹ৴ࡁΈ(໊ࢗը૾ΤϯτϦొ࿥׬ྃ)
 SENT_ENTRY(31),
 /// ໊ࢗը૾ΤϯτϦड৴ࡁΈ(໊ࢗը૾ೖྗ׬ྃ)
 FINISHED_ENTRY(32),
 /// ໊ࢗը૾ΤϯτϦ࠷ॳͷϓϩϑΟʔϧͱͯ͠ηοτࡁΈ
 SET_AS_FIRST_PROFILE(40);
 
 private final int mStatusCode;
 
 FirstMyCardEntryStatus(int statusCode) {
 mStatusCode = statusCode;
 }
 
 public static FirstMyCardEntryStatus of(int code) {
 for (FirstMyCardEntryStatus e : FirstMyCardEntryStatus.values()) {
 if (code == e.mStatusCode) {
 return e;
 }
 }
 throw new IllegalArgumentException();
 }
 
 public int getStatusCode() {
 return mStatusCode;
 }
 
 public boolean isAuthorized() {
 return this == SET_AS_FIRST_PROFILE;
 }
 }
 enumを使う 条件判定にも名前を   つけられる
  3. ドメイン駆動設計のレイヤアーキテクチャ Presentation  Layer 7JFX 1SFTFOUFS Domain  Layer 6TFDBTF Infrastructure  Layer

    Entity %# /FUXPSL Application  Layer Activity アプリケーションレイヤ   アプリケーションの活動を 調整する薄いレイヤ。   ビジネスロジックを含まな い。また、ビジネスオブジェ クトの状態を保持しない。   しかし、アプリケーション の処理理の進み具合を保持す ることがある。  
  4. 実際は… Presentation  Layer 7JFX Presenter Domain  Layer Use-‐‑‒case Infrastructure  Layer

    Entity %# /FUXPSL Application  Layer Activity Presenter,  Use-‐‑‒case   モジュールが存在せず   その実装がすべて Activity/Fragmentに 含まれていた Activity
  5. Activityを軽量量化する Presentation  Layer 7JFX Presenter Domain  Layer Use-‐‑‒case Infrastructure  Layer

    Entity %# /FUXPSL Application  Layer Activity どうやってUse-‐‑‒case部 分を切切り出すか? Activity どうやってPresenter 部分を切切り出すか?
  6. ボタンをクリックしたらMessageをポストして結果を保存 @Override
 public void onClick(View v) {
 switch (v.getId()) {


    case R.id.message_send_button:
 Message message = new Message(postMessageText);
 sendMessage(message);
 break;
 
 default:
 break;
 }
 } private void sendMessage(final Message message) {
 PostMessageRequest request = new PostMessageRequest(message, new Listener<JsonNode>() {
 @Override
 public void onResponse(JsonNode response) {
 JsonNode messageNode = response.get("message");
 EightMessage message = new EightMessage(messageNode); 
 mMessageDB.insert(message);
 mMessageList.add(message);
 // දࣔΛupdate
 }
 });
 request.post();
 }
 MessageActivity MessageDB  mMessageDB;   ArrayList<Message>  mMessageList; -­‐  void  sendMessage(Message);   ボタンをクリックしたら   通信して   あれDBに保存しつつ   画⾯面に反映するActivity
  7. MessageActivity MessageUsecase  mMessageUsecase;   MessageRepository  mMessageRepository MessageRepository MessageDB  mMessageDB;  

    ArrayList<Message>  mMessageList; + void  add(Message);   + void  setUpdateListener(Listener)   MessageUsecase MessageRepository  mMessageRepository; -­‐  void  sendMessage(Message);   sendMessage() add() Listen 通信して結果を保存する   処理理をUsecaseとして分離離 DBに保存しつつ   Listを管理理するクラスを   Repositoryとして分離離 Repositoryからの   updateの通知を受けてViewをupdate
  8. Presentation  Layer 7JFX Presenter Domain  Layer 6TFDBTF Infrastructure  Layer Entity

    %# /FUXPSL Application  Layer Activity Use-‐‑‒case部分を   切切り出せた! Activity
  9. 7JFX Activity 6TFDBTF onClick等のイベント 表⽰示データのセット public class FeedFragment extends AbstractPagerFragment

    {
 
 private RecyclerView mFeedListView;
 private SwipeRefreshLayout mSwipeRefreshLayout;
 private TextView mTalkIconBadge;
 private TextView mNewsIconBadge;
 
 @Nullable
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
 View view = inflater.inflate(R.layout.fragment_feed, container, false);
 mFeedListView = (RecyclerView) view.findViewById(R.id.fragment_feed_recycler_view);
 mTalkIconBadge = (TextView) view.findViewById(R.id.action_bar_badge_icon_count);
 mNewsIconBadge = (TextView) view.findViewById(R.id.action_bar_badge_icon_count);
 mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.fragment_feed_list_refresh);
 return view;
 }
 これまでの実装:   Viewを制御するコードがすべてActivityに
  10. 7JFX 7JFX.PEFM Activity 表⽰示データの取得 6TFDBTF onClick等のイベント public class CreatePostActivity extends

    Activity {
 CreatePostViewModel mViewModel;
 
 @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 mViewModel = new CreatePostViewModel();
 ActivityCreatePostBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_create_post);
 binding.setViewModel(mViewModel);
 }

  11. Presentation  Layer 7JFX ViewModel Domain  Layer 6TFDBTF Infrastructure  Layer Entity

    %# /FUXPSL Application  Layer Activity Presenter部分を   ViewModelとして   切切り出す Use-‐‑‒case部分を   切切り出せた!
  12. Presentation  Layer 7JFX ViewModel Domain  Layer 6TFDBTF Infrastructure  Layer Entity

    %# /FUXPSL Application  Layer Activity Activityは   ライフサイクル の管理理   画⾯面遷移の管理理   に集中すること ができる
  13. $PQZSJHIU˜4BOTBO *OD"MMSJHIUTSFTFSWFE 4BOTBO͸Ұॹʹ৽͍͠Ձ஋Λ࡞͍ͬͯ͘ ஥ؒΛ͕͍ͯ͞͠·͢ɻ 3VCZ 3VCZPO3BJMT ʢ8FCΞϓϦέʔγϣϯʣ $ɼ"41/&5.7$ ʢ8FCΞϓϦέʔγϣϯʣ J04"OESPJEΞϓϦ

      ݸਓ޲໊͚ࢗ؅ཧΞϓϦʮ&JHIUʯ   ໊ࢗσʔλԽ෼ࢄॲཧγεςϜ   ๏ਓ޲໊͚ࢗ؅ཧαʔϏεʮ4BOTBOʯ   ๏ਓ޲໊͚ࢗ؅ཧαʔϏε ʮ4BOTBOʯ   ݸਓ޲໊͚ࢗ؅ཧΞϓϦʮ&JHIUʯ ΤϯδχΞืूத 4BOTBO࠾༻ ݕࡧ SFDSVJU!TBOTBODPN·Ͱ ͓ؾܰʹ͝࿈བྷ͍ͩ͘͞ɻ ڵຯͷ͋Δํ͸