Linguistic Anti-patterns: ソースコードにありがちな不適切な命名を調査した研究
不適切な命名パターンやそれに類似のパターンをLiguistic Anti-patternsとしてまとめてあり、下の論文で報告されています。同様の研究は他にもありますので、興味がある方はこの論文を引用している論文を調べてみてください。
Arnaoudova, V., Di Penta, M., Antoniol, G. Linguistic antipatterns: what they are and how developers perceive them. Journal of Empirical Software Engineering vol. 21, pp. 104-158 (2016)
この記事は論文の一部を紹介したものなので、さらに知りたいという方は論文本体を参照していただければと思います。出版社の公式ページ(購読しているか論文単体を購入する必要があります)か著者のページ(無料で参照できますが、最終版とはフォーマット等異なります)から参照できます。
この論文のTable Iに書いてあるのが、Linguistic Anti-patternsです。この分類はオープンソースソフトウェアArgoUML, Cocoon, Eclipseを調査してまとめたものです。
Table Iの和訳したものは以下のとおりです。論文では、図の補足があるので、詳細に知りたい方は原文を参照いただくと早く理解できると思います。
A.1 "Get" - アクセサ以上の機能
ドキュメント化せずに、対応する属性を返す以外のアクションを実行するgetter。例: getImageDataメソッドは、属性値に関係なく、毎回新しいオブジェクトを返す。
A.2 "Is"がブール値以外を返す
メソッド名が真偽値を返すことを示唆するために"Is"から始めるメソッドの戻り値の型がBooleanではなく、より複雑な型で、ドキュメント化せずにより広範な値を許容している。例: 戻り値の型がintのisValid。
A.3 "Set"メソッドが値を返す
setメソッドの戻り値の型がvoid以外で、適切なコメントで戻り値の型/値をドキュメント化していない。
A.4 単一インスタンスが取得できそうなのにできない
メソッド名が単一オブジェクトが返されることを示唆しているが、戻り値の型がコレクションである。例: Listを返すgetExpansionメソッド。
B.1 実装されていない条件
メソッドのコメントが、コードで実装されていない条件付きの動作を説明している。デフォルトの実装の場合、これをドキュメント化すべき。
B.2 検証メソッドが確認を行わない
検証メソッド(例: "validate"、"check"、"ensure"で始まる名前)が検証しない。つまり、メソッドが検証が成功したかどうかを知らせる戻り値を提供せず、理解するための手順もドキュメント化していない。
B.3 "Get"メソッドが値を返さない
メソッド名が何かを返すことを示唆している(例: "get"や"return"で始まる名前)が、戻り値の型がvoidである。結果のデータがどこに格納され、どのように取得できるかをドキュメントで説明すべき。
B.4 質問形式のメソッド名で回答がない
メソッド名が述語の形式だが、戻り値の型がBooleanではない。例: 戻り値の型がvoidのisValidメソッド。
B.5 変換メソッドが値を返さない
メソッド名がオブジェクトの変換を示唆しているが、戻り値がなく、結果がどこに格納されるかがドキュメントから明確でない。例: 戻り値の型がvoidのjavaToNativeメソッド。
B.6 コレクションを期待するが取得できない
メソッド名がコレクションが返されるべきことを示唆しているが、単一のオブジェクトまたは何も返さない。例: 戻り値の型がBooleanのgetStatsメソッド。
C.1 メソッド名と戻り値の型が整合していない
メソッド名が示唆する意図が、返す内容と矛盾している。例: 戻り値の型がControlEnableStateのdisableメソッド。この不一致は"disable"と"enable"が反対の意味を持つことから生じている。
C.2 メソッド定義のコメントが逆の意味
メソッドのドキュメントがその宣言と矛盾している。例: isNavigateForwardEnabledメソッドが"バックナビゲーション"をドキュメント化するコメントと矛盾している。"forward"と"back"が反意語であるため。
D.1 一つという意味があるが多数を含む
属性名が単一のインスタンスを示唆しているが、その型が複数のオブジェクトのコレクションを格納することを示唆している。例: Vector型のtarget属性。変更が1つのインスタンスに影響するのか、コレクション内の複数のインスタンスに影響するのか不明確。
D.2 名前がブール値を示しているが型が異なる
属性名がその値が真偽値であることを示唆しているが、宣言されている型がBooleanではない。例: int[]型のisReached属性。宣言された型と値がドキュメント化されていない。
E.1 多数を示しているが一つを含む
属性名が複数のインスタンスを示唆しているが、その型が単一のインスタンスを示唆している。例: Boolean型のstats属性。このような不一致をドキュメント化することで、属性の目的を理解するための追加の労力を避けられる。
F.1 属性名と型が反対
属性名がその型と矛盾しており、反意語を含んでいる。例: MAssociationEnd型のstart属性。反意語の使用は誤った仮定を引き起こす可能性がある。
F.2 属性のシグネチャとコメントが反対
属性の宣言がそのドキュメントと矛盾している。例: INCLUDE_NAME_DEFAULT属性のコメントが"除外パターン"をドキュメント化している。パターンが含まれるのか除外されるのか不明確。
このLinguistic Anti-patternsは、技術的負債がソフトウェアエンジニアのコード理解にどのような影響を与えるかを調べるため、技術的負債をタイプにわけた実験を行った際に使いました。この実験では、エンジニアに2種類の技術的負債のパターンを含むコードを読んでもらい、理解に要する時間と正確さを測定しました。
実験では、主に2つのパターンの技術的負債に焦点を当てました:
-
構造的な問題:条件分岐が多く読みにくい構造(適切なデザインパターンの使用で改善可能)
-
命名の問題:不適切な変数名やメソッド名(名前と実際の役割のミスマッチ、名前を適切に変更することで改善可能)
2に関して、本記事の上の分類のうち、今回のコードに含めることができるものをなるべく多く含めました。