ノーUIファイルで作成したiOSアプリが人並みになるまでの道のり


この記事は [Classi Advent Calendar 2017](https://qiita.com/advent-calendar/2017/classi) の3日目の記事です。

ClassiでiOSエンジニアをしている @cl-sawada です。
Classiでは主に高校向けにアプリケーションを提供していますが、そのうちの１つである動画アプリを担当しています。

## **この記事について**

すべてコードで作成された動画アプリの１画面（下図、講義詳細画面）をリファクタリングしてIB導入、一部Swift化してみた内容です。


**講義詳細画面**
![qiita_screen_capture.001のコピー.jpeg](https://qiita-image-store.s3.amazonaws.com/0/218163/a6a3f8a1-afd2-a129-d6c0-26f33bdb7afa.jpeg)



（記事にするまでもなく）おそらくどの現場でも地道なリファクタリングされているかと思います。
実際この内容で学んだこともiOS開発に限った話ではありません。
これは、こんな手順でやってみたよという報告です。
他にもベターなやり方なございましたら教えていただけたら幸いです。
**※ アーキテクチャーの話はでてきません。（今はそれを議論できる状況ではありません）**




## **所感**
- **クラシックな設計からいきなりモダンな設計に移行するのは難しい**
    - 焦燥感からモダンな設計（MVVM, VIPER, Clean,MVVM × RxSwiftなど）にいきなり移行しようと思ってもどこから手を付ければよいか混乱します。**<font color='red'>このアプリは2016年12月頃開発してますが、2012年頃のノウハウベースで作られているフシがある</font>** ので、まずはほどほどにアップデートしてからアーキテクチャーなり考えたほうが機能整理も整理しやすくなります。

- **内製/外注問わず、どの言語（ObjC/Swift）を使うかそんなに問題ではない？**
    - 短納期の場合は開発チームが知っている言語を採用するとして、そのときその言語のベストプラクティスを遵守する、アンチパターンを避ける、だまってリーダブルコードに従うなどしておけば、その後の保守負荷の低減、仕様のキャッチアップが速くなるなあと。
- **「なにこの無駄に見える処理は？」と思っても仕様把握している人に確認を**
    - 「この処理死んでる？」「このViewのためにあるの？」と思っても、一度仕様把握している人に聞いてみてください。結構意図があって残っている場合があります。ちょっとやっかいです。

## **前提環境**
- Objective-C
- 典型的なMVC
- 2016年12月から3ヶ月程度で開発（開発は外注）
- 当時の開発者はもういない
- すべてコードで作成
    - no storyboard, no XIB, no AutoLayout Library
- テストコードなし
- イチからアプリの作り直しはできない

## **何をやったのか**

すべてコードで作成されたアプリの一部をIB&Swift化しました。
直近で画面の見た目の改善案件が何件か控えており、そのまま着手すると上記前提環境ではとにかくつらすぎました。
Interface BuilderでUI構築を行いたいため、まずはstoryboardを導入することを前提にView関連のリファクタリングをはじめました。
以下、ビフォーアフターです。

### **改善前(左) --> 改善後(右)**
![screen_before.gif](https://qiita-image-store.s3.amazonaws.com/0/218163/aaeee165-04db-0f47-d25b-39f299e20b2d.gif)![screen_after.gif](https://qiita-image-store.s3.amazonaws.com/0/218163/28a60220-3402-9fc8-3ca0-678507ea59bd.gif)

これをみて、まずそもそも画面の構成自体が何も難しいところがないじゃないかと感じると思います。
データ０件時のビュー表示、インジケータービューの表示などもやってはいるのですがよくある機能なのでそれも気になりません。（ここでは省略しています）

## **現実は …**

しかし、ビューコントローラーやUI部品は、以下のように継承関係が強めになっており正直どこから手をつけたらよいか最初は困惑しました。（最下層の子クラスはもっと存在します）
一事が万事、もちろんModel層も継承関係が強めです。

※下図の色は、上記改善前の画像の色と対応しています。

##### **講義詳細ビューコントローラー（QTLectureViewController）**

![qtviewcontroller.png](https://qiita-image-store.s3.amazonaws.com/0/218163/76a5303e-3201-d237-51e2-2acebd5816d0.png)

##### **講義ヘッダービュー（QTContentSizeHeaderView）**
![qtheaderview.png](https://qiita-image-store.s3.amazonaws.com/0/218163/0cacaac4-a38b-71ff-abe1-5b50547c2bdf.png)


##### **講義関連セル（QTContentCollectionViewCell, QTLectureDescriptionCell）**

![qtcollectioncell.png](https://qiita-image-store.s3.amazonaws.com/0/218163/dae51434-e357-4152-7cd1-475c656dd796.png)


##### 

```QTLectureViewController.h
@interface QTLectureViewController : QTCollectionViewController
@end
```

```QTLectureViewController.m
@interface QTContentSizeHeaderView : QTCollectionHeaderReusableView
@end
@implementation QTContentSizeHeaderView
@end

@interface QTLectureDescriptionCell : QTToggleTextCollectionViewCell
@end
@implementation QTLectureDescriptionCell
@end

@interface QTLectureViewController () <QTToggleTextCollectionViewCellDelegate>
@end
@implementation QTLectureViewController
@end
```


## **リファクタリングの流れ**

最終的に以下のようなプロセスで徐々にリファクタリングしていきました。
はじめは他の画面でチャレンジしましたが、storyboardを導入準備しないとXIBから取込みなかったので、ビューコントローラーの継承解消までやりきったほうが良いです。

![qiita_refactor_flow.jpeg](https://qiita-image-store.s3.amazonaws.com/0/218163/6905ee5e-405d-b8f6-a282-925853c7e0f5.jpeg)


### **継承解消例**

以下では、画面で表示しているコレクションビューセルの継承解消例です。
ビューコントローラー、ヘッダービューにも同様の手順で進めています。
~~大変地道で苦痛を伴うフェーズです。~~

![qiita_hierarchy_release.001.jpeg](https://qiita-image-store.s3.amazonaws.com/0/218163/3564d659-3580-24c1-ebe3-5955fc6fcbf1.jpeg)

## **最後に**

Classiでは一緒に働くエンジニアを募集しています。
https://www.wantedly.com/companies/classi

明日は @CkReal さんです。