かんたんなプログラムを書くために気をつけていること
iOSアプリ開発をしているObjective-ひろC(@hirothings)です
プログラマーを初めて3年立ちましたが、つねづね”かんたんなプログラムを書く”ことを意識してプログラミングをしています。
そのために気をつけていること、それを実現するために普段どうやってコードを書いているかをまとめました。
※以下、伝えやすいので言い切りの文体にしてます
🤔かんたんなプログラムとは何か
それは
・かんたんに読めて内容を把握できるコード
・かんたんに使えるコード
・かんたんに拡張、改修できるコード
の集合だと定義している。
※テクニックを使わず、初心者でも分かるコードを書けということではない
かんたんなコードを書くのは難しいけど難しいコードを書くのはすごい簡単
・行き当たりばったりで分岐を書く
・isXXのような変数がメンバ変数としてあり、頻繁に変化する
・長すぎるメソッド、1000行を超える責務過多なクラス..etc
無計画にコードを書けば、解読不能なコードを書くのはすごい簡単。
これをやってしまうと他人も読みづらいし、数ヶ月後の自分でさえ何をやっているか分からない😟
🧐かんたんなコードを書くときに大事にしていること
色々意識していることはあるけど、根底にあるのはシンプルな考えです。
状態をむやみに増やさない
前述したようにisXXのようなメンバ変数が複数定義されてて、1000行以上のクラスの中で幾度となく変化していたら訳がわからない。
メソッドは適切な単位に切り離されていても、その中で相互にその変数を参照して変更していたら、メソッドとメソッドの間に依存関係が生まれる
メソッドを呼ぶ側が呼び出しのタイミングに注意するコードがあったら、それはかんたんじゃないから良くない。
isXXのようなフラグがどうしてもいるなら、そのフラグを使って分岐するコードを1クラス, メソッドにまとめるなど、後からコードの変化を読みやすいように気をつけている。
その実装ができずに上記のようなコードにしかできない場合は、そもそも分岐ごとにクラスを分けるとか設計から考え直した方が良い。
クラス・メソッドの責務を1つにする
単一責任の原則と呼び、大事な原則の1つ。
コードが長く様々なことをやっているクラス・メソッドは分かりづらい
あとで使う人、改修する人が最後の行まで読み進めないと何ができるのか分からない or コメントを丁寧に書かないと意図が伝わらないから。
そのようなクラス・メソッドになったら、分解した方が良い。
個人的な経験上、 〇〇Manager というクラスは大体怪しい..
責務を分けられていないと、意味の広い名前になる
では、どの単位で分ければ良いかというと
あとで紹介するオブジェクト指向設計実践入門にわかりやすい判断の仕方がある
“クラス・メソッドの役割が何であるか質問し、一文で責任を語れるようにしてみる”
それを意識すると、どういったクラスに分割するかどう依存性を注入するか(DI)という設計を考えるようになり、アーキテクチャの選定や設計ができるようになってくる。
📲普段どうやってプログラミングをしているか
では、普段かんたんなプログラムを実現するためにどうプログラミングをしているかというと、
1. 機能を実現するためのTODOを1メソッド単位に切り出せるまで洗い出す
2. そのTODOを担当する登場人物を書き出してみる
ということをコードを書く前にいつもやっている。
例えば最近作った「パスコードロック画面」の機能を例に挙げてみると
PasscodeModel.swift
[役割]パスコードを管理するモデル
[TODO]
・保存
・削除
・更新
・判定
・エラーハンドリング
・5回パスコードの入力に失敗したらViewに通知する
と言った具合だ。
プログラミングする前にTODOとそれを担当する登場人物を洗い出すと、何と何のオブジェクトをDIするか考えるベースとなる。また、具体的なコードを書いた後に大きく手戻りがでるリスクを減らせる。
最適化を急ぎすぎないこと
前述したように、かんたんなプログラムを書くために設計は大事だし、こだわりたい部分だが、最近は最適化を急ぎすぎないことを頭の中に置いている。
設計にこだわりすぎると往々にして難しい設計に凝ったり酔うことがある。そしてそういうコードは、
・ある時点のコードを最適化しすぎて改修が困難になる場合がある
・レビューの時点では綺麗なコードなのでレビューでは指摘しづらい
という側面がある。
自分の場合は、前述のパスコードロックの画面を作ったとき、パスコードに関連するほぼ同じようなコードだけれども微妙に違う機能
・パスコードロック解除
・パスコード登録
・パスコードアップデート
その微妙に違う機能を開発初期からインターフェースに切り出したりまとめようとして、手戻りが発生して時間がかかってしまった
・最適化を急ぎすぎて中間のコミット履歴の悪いコードを認めようとしなかった
・インクリメンタルに開発する意識が抜けていた
のが敗因だ。
もちろん最初から無駄のない完璧なコードが書けるに越したことはないが、それは難しい。
デッサンのように最初にざっくり骨組みを作って、後から細部を磨いていく方が作り方としては早いし良いと思って実践している。
📝かんたんなプログラムを書くスキルを磨くために
個人的にやったことや考え方の参考になった記事を紹介します。
本を読む
オブジェクト指向設計実践ガイド
オブジェクト指向でプログラミングをするうえで、大事なことが具体的なコードと共にまとめられている良書。めちゃくちゃ参考になってたまに読み返している
UNIXという考え方―その設計思想と哲学
UNIXの小さく単純なプログラムを実現した哲学、思想がまとめられた良書。普通に読み物として面白い
ブログだとこの記事をたまに読み返す
プログラミング中級者に読んでほしい良いコードを書くための20箇条
良いコードを読む
オープンソースのコードや、信頼している同僚のコードなど読むのは言わずもがな大事。個人的にすごい参考になったのは、下記のUserDefaults(※1)をSwiftらしくラップして利用する下記の記事のコードだ。
・キーを文字列ではなくEnumで使えるようにしてタイプセーフにしている
・KeyNamespaceableというprotocolでネームスペースを作っている
・利用するときエディタの補完が効いて、かんたんに使えるようにしている
という点が素晴らしく、テクニカルなコードを書いてかんたんなプログラムを実現している良い例だと思う。
※1 UserDefaults: iOSのローカルデータ保存領域のこと
(参考)悪い方が良い
Googleで働いており、Turing Complete FMというポッドキャストをやっているRui Ueyamaさんの「悪い方が良い」原則と僕の体験談というnoteの考え方が好きで参考になった。
実装の単純さの重要性をlldというリンカの書き直しの実績をもとに簡潔にまとめている。
Ruiさんのようなスーパープログラマーは、難しいコードをゴリゴリ書いてるイメージを勝手にそれまで持っていたが、全然違った。
複雑な事象をデザインしてかんたんなコードに落とし込むこと、その設計自体が非常に高度なテクニックなのだと気付かされた
💾習慣化する
上記のような本を読んだり、アーキテクチャを学んだとき、日々の仕事に落とし込んでそれを習慣化させることがとても大事だと思う。
自分は、難しいコードや複雑なコードを書いているときは、大体コードとして表現する事象についての整理や設計がきちんとできていないと思って、
一旦手を止めてクラスを分けたりアプローチを変えるなど検討することを常に習慣化している。
まだまだ自分も道半ばだけど、常に複雑になっていないかをチェックしながらコードを書けば、だんだんとかんたんなプログラムが書けるようになってくると思う。
最後に
どの言語のプログラミングをしてる人でも分かりやすく書いたつもりですが、読みづらかったらコメントかTwitterにメンションください。
記事が気に入って良ければサポートお願いします!アプリ開発の資金に補填します。