TL;DR
- ユティリティーとヘルパーの違いは曖昧
- ユティリティークラスはプライベートコンストラクタを持ちstaticメソッドを公開しているパターンが多そう
- ユティリティーパッケージ、ユティリティークラスやヘルパークラスの命名には単数形(~Util / Helper)を用いるパターンと複数形(~Utils / ~Helpers)を用いるパターンがある
- ヘルパークラスはutilパッケージ内部に定義されているパターンが多そう
- とはいえ、ユティリティークラスやヘルパークラス、またはそのパッケージの命名に関してはチームの中で統一された考え方がありみんな納得感あればそれで良さそう
- うちのチームだとこうしているよ、というような知見の共有などいただけると幸いですm(__)m
ユティリティークラスとヘルパークラスの違いって曖昧だな、と、最近モヤモヤと感じています。
よくよく考えてみると、「ユティリティークラスとはこういうクラス」、「ヘルパークラスとはこういうクラス」というふうに深く意識したことがあまりなかったです。それはそれでどうなのよ、という意見もあるかもしれません。なぜ意識しようと思ったかというと、最近担当しているプロジェクトのユティリティークラスのコードを読んでいた時に「この関数はユティリティークラスにあるべき関数なのかな?」とふと疑問に思っている自分がいたりしたからです。なのでまずは自分なりの考えをまとめてよう、と思った次第です。
先に書いておくと、言語、プラットフォーム、もしかしたら時代によってもユティリティークラスとヘルパークラスの違いや考え方が異なるかもしれないです。今回はAndroidアプリケーション開発にフォーカスしています。
- 別に困らないからそこまで違いを意識する必要ないのでは?
- ユティリティークラス、ヘルパークラスは悪だ!
- 拡張関数でええやん
- 不毛だな(゚∀゚)
という意見もあるかもしれませんが、ここではあまり意識していません。コメントでもTwitterにてメンションやDMでも良いので、勘違いやご意見、うちのチームだとこうしているよ、というような知見の共有などもしありましたらいただけると本当に嬉しいです!
そもそも
以前、一人で開発を担当していたプロジェクトでは、ユティリティークラスはアプリケーション独自の仕様への依存がなく、どのアプリケーションにも転用できるようなstaticなメソッド群を定義したクラス、ヘルパークラスはアプリケーション独自の仕様だったり特定のライブラリに依存したstaticなメソッド群を定義したクラスと定義していたつもりでした。改めて見返してみると、常にこの定義に沿っているわけではありませんでした。。
改めて、ユティリティークラス、ヘルパークラスとはなんだろう、ということで検索してみました。
まずはユティリティークラスから見ていきます。たくさんの記事がヒットしましたが、Quoraの記事の回答を引用します。
What is a utility class? - Quora
A utility class is one which:
- Has no state (fields) of its own, so all the methods can be class methods (static) rather than object methods (requiring an instantiation of an object)
- Provides methods for multiple other classes (shared code)
上記Quoraの回答によると、
ユティリティークラスは、下記に該当するクラスだそうです:
- 独自のstateを管理せず全てのメソッドがクラスメソッド(static)にできるクラス
- 他複数クラスへメソッドを提供するクラス(shared code)
ヘルパークラスのほうも検索してみます。
上記stackoverflowの質問では、helper "objects"という単語が使われています。もしかしたらヘルパークラスはインスタンス化して利用するクラスという認識が、質問を記載した方にはあるのかもしれないです。
stackoverflowの回答の1つを引用します。
These are objects that "sit to the side" of the main body of code, and do some of the work for the object. They "help" the object to do it's job.
ヘルパーオブジェクトは中心となるコードの隣で特定のオブジェクトのために仕事を肩代わりするオブジェクト。特定のオブジェクトの仕事の"手助けをする"オブジェクトである
というようなことが書いてありそうです。ヘルパークラスがなぜ"ヘルパー"なのかはなんとなく理由がつきそうです。この記事ではヘルパークラス
という呼び方をしていますが、もしかしたらヘルパーオブジェクト
という呼び方がより一般的なのかもしれないです。
Androidフレームワークのコードを参考にしてみる
ここでAndroidフレームワークのユティリティークラス、ヘルパークラスをそれぞれ参考にしてみます。
Util / Utils
Search results for "util" | Android Developers
ユティリティークラスに関してAndroid Developerサイト上で検索してみると、java.utilパッケージ内のクラスがたくさんヒットします。代わりに、GitHub上のAOSP mirrorのほうを見てみます。utilパッケージを覗いてみます。
クラス群の命名に注目してみると、下記に気づきました。
- Utils接尾語がついているクラスがちらほら
- Helpersクラスも一つだけ(ContainerHelpers.java)
- JsonWriter、Logなど、UtilsやHelpers接尾語がついていないクラスがほとんど
- プライベートコンストラクタが定義されていてstaticクラスとして利用するものが多いですが、インスタンス化して利用するクラスも含まれている
次はSupportライブラリのcore-utilsを見てみます。
NavUtils、ColorUtils、MathUtilsのようにUtils接尾語が付与されているクラス名もあれば、そうではないクラス名もあります。また、AOSP mirror同様、Helperクラス(PrintHelper)も内包されています。
Square社のOSSのコードを参考にしてみる
次はAndroid界隈では有名なSquare社のOSSのコードを参考にしてみます。(ここでは取り上げているライブラリについての説明などは記載していません。)
OkHttp 3
※2020/08/11 追記:こちらのクラスは追記時点で存在しなくなっておりました。
OkHttp 3にはinternalパッケージ配下にUtilという名前のクラスが存在します。
プライベートコンストラクタが定義されています。internalパッケージ配下に存在しますが、定数やメソッドはpublicスコープなのでアプリケーション側からも呼び出しができそうです。
/** Junk drawer of utility methods. */ public final class Util { ...
というコメントがあります。個人的にはユティリティーメソッド群を寄せ集めしただけのクラスなのかなという解釈をしています。
Picasso 3
Picasso 3にもユティリティークラスが存在します。こちらはUtilsという名前です。
Picasso 3のUtilsクラスにもプライベートコンストラクタが定義されているため、staticメソッド呼び出しのみの利用が想定されています。Picasso 3のUtilsクラスは、クラス自体やメソッドが全てパッケージスコープとなっているようです。余談ですが、もともと依存があったかどうかは調べきれていませんが、Picasso 3のUtilsクラス内部ではOkioのクラスが利用されていることがわかります。
Okio
※2020/08/11 追記:こちらのクラスは追記時点で存在しなくなっておりました。
Okioにもユティリティークラスが存在します。Okio 2に向けてKotlin化作業が進み、UtilクラスはKotlinで書き直されています。OkioはOkHttpと同様、Utilというクラス名が採用されています。
まとめ
もうまとめなの!?ヘルパークラスはどうした!?と思われるかもしれませんが、体力が尽きそうなのでこのあたりで身勝手にもまとめさせていただきます。
Androidフレームワークや著名なOSSライブラリを複数開発するSquare社のソースコードを参考にと思い読んでみた結果、個人的には下記のことが分かりました
- ユティリティーとヘルパーの違いは曖昧
- ユティリティークラスやヘルパークラス、またはそのパッケージの命名に関してはチームごとに統一された考え方があれば良さそう
- ユティリティークラスはプライベートコンストラクタを持ちstaticメソッドを公開しているパターンが多そう
- ユティリティーパッケージ、ユティリティークラスやヘルパークラスの命名には単数形(~Util / Helper)を用いるパターンと複数形(~Utils / ~Helpers)を用いるパターンがある
- ヘルパークラスはutilパッケージ内部に定義されているパターンが多そう
前プロジェクトではhelpersパッケージ内に~Helperクラスを定義していましたが、AOSPの場合、utilパッケージ内部にヘルパークラスを内包するパターンが多く見られたのが意外でした。きっとユティリティーという概念の中にヘルパーという概念が存在するのだろうな、というふんわりとした印象を覚えました。
とはいえ、調べてきた上で「けどやっぱりutilパッケージとhelperパッケージわけたほうがよくないか」という考えだったり「クラス名の単数形、複数形は統一したい」「パッケージ名に関しては複数形にしたい」というようないわゆるエゴのようなこだわりのようなものは消えていないので、これからもチームの他のメンバーさんたちと議論しながら納得感持って開発していきまっす。
改めて、うちのチームだとこうしているよ、というような知見の共有などもしありましたらいただけると嬉しいです。
以上です!