ぎにょろぐ

Androidアプリ開発に関する事やその他雑記など

いいなと思ったプログラミングの原則・法則まとめ

YAGNI

You Aren't Gonna Need It (その機能は必要無いよ!)の略称。

「HogeHogeの改修したい時のためにこの仕様にしておいた方がいいよね」といった「もしも」のために作った機能は、結局の所ほとんど使われることはないため、工数の無駄であるという考え方です。

Extreme Programming の文脈から登場した概念とのことです。

このトピックに関するインターネット上の記事が散見されますが、このように抽象度の高い概念だとどうしても自分の経験に基づく解釈をしがちなのかなと感じました。

例えば、YAGNIはソフトウェア実装の原則。直訳は「そんなモン要らんって!」 - ベルリンのITスタートアップで働くソフトウェアエンジニアのブログ においては、「仕様を満たす上での技術選択におけるオーバーエンジニアリング」に対して、 YAGNI ~ 予想でモノを作るな | 悪態のプログラマ の記事では、「CSV出力機能」などの要件レイヤーの部分に対する事に大してYAGNIの観点から批判をしています。

しかし、ともすれば設計をクリーンに保つためのリファクタリングなどもオーバーエンジニアリングとして捉えられてしまうため、常にこの概念に対する解釈をアップデートしていく必要があるでしょう。

私的には、この原則は後者の機能レイヤーに対しての原則だと解釈しています。例に出したCSV出力機能レベルの事は言わずもがなですが、もう少し細かい事例を想定してみると、

  • この画面は他画面から遷移されるかもしれないから、より汎用的・独立的に使えるようにしよう。(今は完全に遷移元の画面に依存した作りになっている)
  • エラー画面を動的に変更したり、エラー文言が変わるかもしれないから、それらに耐えうる汎用性の高い仕様にしよう。(今はエラー画面パターンは完全に固定)

といった提案に対しても、YAGNIの原則を当てはめてあえて限定した処理しか記述しないようにすべきであると思います。

一般的に、Viewコンポーネントやオブジェクトが機能を提供しているメタ構造自体が、コードを読む上で現在の仕様把握の手がかりとなるケースがあり、用途不明の機能はその理解を妨げ、結果保守における工数が増加してしまうからです。

また、一般的にDDDの文脈におけるモデル駆動の設計は、クラスも増えるためオーバーエンジニアリングに見られがちですが、実際には提供する機能を制限したりプリミティブ型の取り扱いをなくして、値オブジェクトとして取りうる値の制約を明示したりと、プリミティブ型をそのまま取り扱った手続き型プログラミング的書き方で「コードは汚いけど工数を極力少なくしてYAGNIを実践した」という主張より、どこまでが提供すべき機能で、どこまでが提供すべきでない機能であるかを明示している分、YAGNIをしていると自分は感じます。

Don't tell, ask

新装版 リファクタリング 既存のコードを安全に改善する | MartinFowler, 児玉公信, 友野晶夫, 平澤章, 梅澤真史 | 工学 | Kindleストア | Amazon の著者が提唱した概念。

Martin Fowlerが書いた記事 TellDontAsk によると

Tell-Don't-Ask is a principle that helps people remember that object-orientation is about bundling data with the functions that operate on that data.

(約 : Tell-Don't-Ask はオブジェクト思考がデータ構造とそのデータを処理する関数と紐付ける事であることを思い出させてくれる原則である)

と述べています。詳しい事は上記の記事や他の記事を参照。

デメテルの原則 と似たような領域の話ですが、デメテルの原則は具体的な「オブジェクトが保持するインスタンスのメソッドを参照しない」という事にフォーカスを置いているのに対して、ドメインを表現する事にフォーカスしている概念と感じました。

下記のコードのように、プロパティを参照して呼び出しもとで計算を行うことはよくあるのではないでしょうか(あまり上手いたとえでなくて申し訳ないです。)

// wifeが呼び出し元に対して、nameプロパティをtellして(伝えて)いる
val firstName = wife.firstName
val lastName = "Stiller"

println("married name is " + firstName + " " + lastName)

このような処理を、できるだけオブジェクト自体に振る舞いをもたせようとすると、おそらく下記のような作りになるでしょう。

println(wife.marriedName(husband))

class Wife(private val firstName : String) {
     fun marriedName(lastName: String) : String {
          return this.firstName + " " +  husband.lastName
     }
}

下記の方が不要なプロパティの公開も無く、アプリケーションの仕様用途がより明確となる構造となっているためより良いオブジェクトのように見えます。

ただ、上記の記事でMartin Fowlerは Tell Don't Askも銀の弾丸ではない旨を述べている。病的なまでのGetter撲滅により可読性の低い構造化をしてしまう恐れがあったり、オブジェクト同士の効果的な連携を阻害してしまう恐れがあるとのことです(このあたりはまだ理解できていません)。

But personally, I don't use tell-dont-ask. I do look to co-locate data and behavior, which often leads to similar results. One thing I find troubling about tell-dont-ask is that I've seen it encourage people to become GetterEradicators, seeking to get rid of all query methods. But there are times when objects collaborate effectively by providing information.

参考

YAGNI - Wikipedia

その1 YAGNI(ヤグニ)の原則でいこう

Martin Fowler氏が"Yagni: You Are Not Gonna Need IT"について語る

YAGNIはソフトウェア実装の原則。直訳は「そんなモン要らんって!」 - ベルリンのITスタートアップで働くソフトウェアエンジニアのブログ

YAGNIを実践する(翻訳)

TellDontAsk

何かのときにすっと出したい、プログラミングに関する法則・原則一覧 - Qiita

デメテルの法則 - Wikipedia