設計を学ぼうと思っても、理解しづらくてゲボりますよね _(´ཀ`」 ∠)_
一般的な説明があっても iOS だとどんな感じだろう?ってこともあるし、「漢字は読めるけど書けない」みたいなノリで「書けるけど説明できない」みたいなこともあったので、さらっと読めるレベルに砕いて記載していきます。
読み終わったあとに、設計ってこんな感じなのかってなれたら嬉しいです。
設計とは
設計とは、”関心の分離” によって、単純な問題のモジュールの集合として切り分けることです。
これだけだと「はい?」って感じですが、ユーザー情報を表示する画面で例えると分かりやすいです。
“ユーザーデータを取得するためにサーバー通信を行い、その間に画面(レイアウト)を組み立て、ユーザーデータ取得後に表示する” という一連の流れをそのまま実装すると viewDidLoad() に全ての処理を書きますが、細かく分けると以下のようになります。
1 2 3 4 5 6 7 8 9 |
// サーバー通信 func fetchUserData() {} // レイアウトの組み立て func setupButtons() {} func setupLabels() {} // ユーザーデータ表示 func setupTableView(viewData: UserViewData) {} // 名前はテキトーですさーせん 三└(┐卍^o^)卍ドゥルルル // |
超絶ざっくりですが、プログラムを関心(機能の振る舞いや目的)ごとに分割して、無駄な重複をなくして構築することです。
コードは書くよりも読む時間の方が長いので、質問された時に答えられるようにすることが大事です。
その実装が “どう行われているか” ではなく “なんなのか” を示すようにしましょう。
なぜ設計が必要なのか
継続的にアプリ開発をしていくには、新しい仕様を実装したり、既存コードの改修が必要になってきます。
昔に比べてアプリで出来ることや画面数も増え、iOS のアップデートにも対応しないといけません。
複数人での開発ともなると、他の人が書いたコードも把握しないといけませんが、プロジェクトメンバー全員が全ての仕様を把握するのは無理ゲーです。
画面1・画面2の両画面でユーザーデータを取得する処理がある場合、設計されてないとそれぞれに同じコードを書くことになり、ユーザーデータを取得する画面が増えるたびに重複も増えます。
また、取得処理に変更があった場合、全ての画面で書き換えないといけません。
説明が膨大になるので設計の詳細は省きますが、取得する処理を1ヶ所にするだけでも重複が省かれ、書き換える場所も1つで済みます。
また、命名規則の決まりがないと、ユーザーデータの取得を行うメソッドだけでも loadUserData()、loadingUserData()、fetchUserData() みたいにバラバラになる可能性もあります。
可読性が落ちると効率も落ちてしまうので、このような問題を出来るだけクリアにして問題を減らしていくために、設計が必要になってきます。
設計をするために
オブジェクトが責任を持って行わなければならない振る舞いのことを “責務”と言います。
責務の分割が適切に行われた状態は、高凝集(モジュール内で責務がまとまっている)、疎結合(モジュール同士では責務が分かれている状態)とされており、これが曖昧だと拡張性やメンテナンス性が低く、見透しの悪いコードになってしまいます。
責務を適切に行うためには、責務の範囲を理解し、ちゃんとした名前を付けてあげることです。
責務の範囲を理解する
責務について書かれた海外の記事で “日付(Date)を文字列として出力するために Date 型に extension として追加する” という例えがありました。(サイト見つけたら貼り付けます)
1 2 3 4 5 6 7 8 9 |
extension Date { static var string: String { let dateFormatter = DateFormatter() dateFormatter.dateStyle = .medium dateFormatter.timeStyle = .short dateFormatter.locale = .current return dateFormatter.string(from: self) } } |
ワンポイントで使うのであれば一見便利そうですが、これは Date 型の責務の範囲を超えています。
公式ドキュメントには “Date は特定の暦法やタイムゾーンに依存しない単一の時点をカプセル化したもの” と記載されています。
そのため、文字列に変換することは DateFormatter や Calendar の責務であって、Date の責務ではありません。
なぜこれを覚えていたかというと、僕がやっていたからです。笑
責務にはちゃんとした名前を付ける
意外と大変だったりします。笑
ただ、Swift の公式ドキュメントである API Design Guidelines には、メソッドや変数など、プログラムで使われるインターフェースに対し、以下の3つの原則が記載されています。
・使い道を明確にする(分かりやすさが重要)
・名前は長くてもいいので、明確であることが重要
・すべての宣言に対して、ドキュメントコメントを書く
会社やプロジェクトによっては「短く簡潔に」と唱えてるところもありますが、公式だと逆にアナウンスしています。
設計を正しく行うために、責務の範囲を理解し、ちゃんとした名前を付けないといけません。
さいごに
次に進むと長くなって区切りが悪いので、一旦ここまでにします。
メソッド名などは会社で決まってるところが多いので、すでに実装されている名前に沿ったものを付けることは出来ますが、責務は型も理解してないといけないので、大変だったりします。
すべてを覚えることは出来ないので、経験を積んでくしかないと思います (☝ ˘ω˘)☝
設計は宗教…
コメント