読者です 読者をやめる 読者になる 読者になる

UZABASE Tech Blog

株式会社ユーザベースの技術チームブログです。 主に週次の持ち回りLTやセミナー・イベント情報について書きます。

NewsPicks(iOS)の設計思想

NewsPicksチームインターン生の保田です。
主にiOSアプリ開発のお手伝いをしております。
iOSアプリを作っていて悩ましいな、と思うのが、同じ機能を持つがiPadiPhoneで見た目が違うページをどう設計していくか、ということです。
 
ちょうど僕が関わった、NewsPicksの特徴的な機能である「ニュース中間ページ」をどのように設計したかについてお届けいたします。
 
 
f:id:uzabase:20141217174422p:plain
f:id:uzabase:20141217175413p:plain
f:id:uzabase:20141217175439p:plain




NewsPicks上でニュースをみるとき、上図の左から右の流れで画面を切り替えます。
この中の真ん中の画面(ニュース中間ページ)の設計についてご説明していきます。
 
 
Season1. 単一仕様時代
 
当初は、次のような単純な仕様でした
 - 「フォローしているユーザー」セクションで、コメントを表示
 
 - 「その他のユーザー」セクションで、コメントを表示

f:id:uzabase:20141217175927p:plain



ただし、並び順に関してはサーバー側で『時系列順』『Like順』でソートされたものを受信して、そのまま表示していました。
 
当時は次のようなクラス図になっていました(メソッドは省略)。

f:id:uzabase:20141217180037p:plain

 

ControllerにはiPhone, iPadで共通の処理が双方に書かれていたため、メンテナンス性が低いものになっていました。また、NewsTableViewにはコメントが表示されるのですが、コメントの有無の判定、データの保持などの処理も行っており、ViewとLogicが切り分けられていない典型的なアンチパターンになってしまっていました。
 
 
 
Season2. 人気コメントの誕生
 
 
次に、人気ニュース一覧からニュース中間ページに遷移した場合、Likeがたくさん付いているコメントを「人気コメント」というセクションで上位に表示するという仕様が産声を上げました。

f:id:uzabase:20141217180055p:plain


 
 
仕様を整理すると、下記のようになります。

f:id:uzabase:20141217180124p:plain

 
そこで、以下のような設計に変更しました。

f:id:uzabase:20141217180143p:plain

 
Commentsというクラスを作成し、NewsTableViewから表示するコメントの表示内容、コメントのソートなどを切り離しました。これで、ViewからLogicを少し切り離すことができました。
 
CommentsWithTrendingCommentsはCommentsを継承した、人気コメントを表示するためのクラスです。NewsTableViewがどうCommentsを生成すれば良いか知っていて、それをControllerが知っているという設計です。実装の詳細を知らないと使えないクラスはイケてません。
 
 
 
Season3. 検索機能の実装と、連載企画のスタート
 
 
NewsPicksオリジナル連載企画がはじまり、中間ページに以下のようなページが仲間入りしました。
 

f:id:uzabase:20141217180204p:plain

 
上のほうに連載名が書いていたり、「記事に登場するユーザー」というカテゴ リが追加されたりしました。
また、検索機能が追加され、コメント検索の結果から遷移すると「ヒットした コメント」というカテゴリを表示することとなりました。
仕様を整理すると、下記になります。

f:id:uzabase:20141217180427p:plain

 
それに伴い大幅な設計変更を行い、以下の様な設計になりました。

f:id:uzabase:20141218143953p:plain


f:id:uzabase:20141217180515p:plain

 
大工事です。
5個しか無かったクラスが
20 個近くになりました。緑色のクラスが実際に呼び出されるクラスです。
共通部分は
Abstract に集約し、コメントのロジックは PickerCommentsCategorizeLogic が責務を持 ち 、 データはCategorizedComments で授受されそのまま表示すると正しいセクションが表示されます。
また、
Factory Method パターンを導入したことによって呼び出し側は Abstract など実装の詳細は一切知りません。 しかし、まだ改善の余地があります。『AbstractNewsSummaryController』の 親クラスが iPad, iPhone によって分かれてしまっていて、全く同じ処理が iPhone, iPad のそれぞれに書かれてしまっています。 



Season4. 更なるリファクタリング

Season3 で残ってしまった重複コードを削除すべく、リファクタリングを
行いました。
iPad だけが継承している TransitionController は、Controller
の遷移方法に関する責務を持っていました。これをを Helper として存在さ
せ、標準の
UIViewController を継承できるようにしました。



f:id:uzabase:20141217180544p:plain


こうすることで共通部分を抽象クラスへ追いやることができ、具象クラスの重複コードが撲滅できました。




ここで、season3でFactory Method パターンを導入していたため、呼び出し側では全くコードの変更が必要ありませんでした。GoF さまさまです。

まとめ




NewsPicks では、同じ機能をもつが iPad iPhone で見た目が違うページを、下記のような戦略でメンテナンス性の高い設計で実装しています。

- View, Logic, Controller を切り分ける

- 具象クラスに点在する共通処理を抽象クラスに追いやる

- Factory Method パターンでインスタンスの生成方法を隠すことにより、後々の変更に強くする

サービスローンチ時に、様々な試行錯誤を行いながら徐々にサービスを成長させる過程で、負債コードをためてしまうのは致し方ないことです。しかし、適切な手順で設計を変更すれば必ずコードは綺麗になります!





NewsPicks では更なるグロースに向けて、一緒に戦ってくれるエンジニアを募集しております!

インターン生でも設計から携わらせていただけるのでとても勉強になります!


興味をお持ちいただいた方は Wantedly などからご応募ください!!