[Archeology Live]シングルに関する恥ずべき話

対象者:Java Junior、ハリウッド愛好家、プロのシングルトンライター









コメントや提案は大歓迎です。 これは私の最初のビデオであり、そのようなコンテンツが必要かどうかは完全には明らかではありません。 これは、Javaハブへの訪問者のみを対象としたクローズドアルファテストであると考えてください。







以下はフルテキストのトランスクリプトで、視聴に時間をかけたくない人です。







エントリー



こんにちは、Habr! 夕方になって、真剣に話をする時が来ました。 恥ずかしい話をしたいです。 シングルトン。







事実、私はいつも友達からシングルトーンを破壊し、レビューコードで春を刈る方法を酒から聞いています。春はスラグだからです。 そして今、私の強みは我慢できなくなりました。すべてのゴミについて説明しましょう。







まず、シングルトンが恥である理由。







シングルトンについて語る最も古い本(まあ、少なくとも私が自分の目で見た最も古い本)は1994年に書かれました。 これは、ギャング、ヘルム、ジョンソン、Vlissidesの4人のギャングによる本「Design Patterns」です。

何歳か考えてみてください。 1994年に何をしましたか? 私たちの同僚の中には、今年生まれていない人もいます。













または、私の人生の2番目の愛は、2002年に書かれたケントベックの本Test Driven Developmentです。













そして、シングルトーンについては次のとおりです。













古さを揺さぶるのではなく、巨大なボタンアコーディオンがシングルトンハットですべてであることを示すためにこれを伝えています。 シングルトンは、まだ生まれていないときや小学校で勉強していないときに悪用されました。













したがって、原則として、公の場でシングルトーンを議論するのは恥ずべきことのように思えます。 これについては、親しい友人、あなたの最愛の女性/男性、そしてあなたと、親愛なるHabrとだけ話すことができます。







ブライトサイド



ここでは、すべての専門家が、彼らのお尻でシングルトンの危険性を感じていることは明らかです。 しかし、ロバは最良の指標ではありません。不安をなんとか言葉で表現しましょう。 悪いシングルトーンとは正確には何ですか?







グローバルステータス



シングルトンは主にグローバルな状態です。 不可分で管理が不十分なグローバルスコープを1つ取得します。 この管理性の欠如はそれ自体が問題です。







これを何らかの方法で説明するために、シングルトン内に何らかのステートマシンまたは通信プロトコルが隠されていると想像してください。 これを自動的にテストする場合、a)シングルトンに触れるすべてを同時にテストする必要があり、b)最悪の場合、これらのテストは特定の順序で実行する必要があります。







テストを次々に実行する必要がある場合、不要なものを捨てることはできません。12時間以内に1つのテスト実行が行われる状況にすぐになりますが、これは非常に悪いことです。







明示的および暗黙的



明示的が暗黙的よりも優れているというよく知られた原則があります。 ちなみに、この原則はPEP 20で規定されており、「Python言語の禅」として知られています。













オブジェクトをアドレスに正確に転送するのではなく、グローバル状態に転送すると、コード内のリンクが非表示になります。 これは非常に暗黙的です。 その結果、コードはすぐに魔法に変わります。 それは何らかの形で機能しますが、それ自体で、あなたの力ではなくなります。







単一責任の原則



唯一の責任の原則。 つまり、略語SOLIDの文字Sです。 この略語は、ジャビスタの生活の中で最も重要です。 私は彼女をとても尊敬しているので、彼女と入れ墨をしたいと思っています。







この原則は、かつてロバート・マーティン(ボブおじさんとして知られている)によって導入されました。













彼は、各オブジェクトには1つの責任があり、その責任はクラスに完全にカプセル化される必要があると主張します。







私たちがシングルトンを作る場合、彼の即時の義務に加えて、彼は自分のライフサイクルを管理するという別のタスクを任せます。 コードを呼び出すことでオブジェクトの表示方法とタイミングを決定する必要がなくなり、オブジェクトへのアクセスを整理するのは通常の環境ではありませんが、これらはすべてシングルトンクラス内に詰め込まれています。 ある意味では、彼は本当にこのタスクを実行しますが、曲がりくちゃで惨めです。 実際、1つの石で2羽の鳥に遅れを取ろうとするコードのように。







強いつながり



シングルトンを使用するすべてのコンポーネント、または神が禁じている-それを介した通信は、即座に密接に接続されることが判明しました。 多くの場合、バウンドは解く必要があります。たとえば、テストを記述するためです。 また、シングルトーンで重くコーティングされたコードのテストは非常にイライラします。 1つのシングルトンでさえ、TDDを使用するテスターとプログラマの両方に深刻な負担をかける可能性があり、孤立した機能のデモンストレーションを台無しにします。







Javaの仕様



Javaにはシングルトンを記述する特別な方法はありません。 したがって、それを記録する多くの方法があり、それらはすべていです。







まず、すべてを静的フィールドまたは列挙に押し込むことができます。







public class Singleton { public static final Singleton INSTANCE = new Singleton(); }
      
      





 public enum Singleton { INSTANCE; }
      
      





しかし、これは怠zyなオプションではなく、必要ありません。

必要に応じて列挙型を遅延させることもできますが。







同期化された状態ですべてを突き出すことができます。







 public class Singleton { private static Singleton instance; public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
      
      





しかし、最も典型的な使用例では、実際に同期を象徴するのはブレーキです。







または、二重チェックのロックオプションを使用する必要があります。







 public class Singleton { private static volatile Singleton instance; public static Singleton getInstance() { Singleton localInstance = instance; if (localInstance == null) { synchronized (Singleton.class) { localInstance = instance; if (localInstance == null) { instance = localInstance = new Singleton(); } } } return localInstance; } }
      
      





さらに下劣に見えます。 さらに、Java開発者自身がこの形式の執筆に対する態度を表明しました。







「スレッドが同期せずに通信できるようにするために提案されている、二重チェックロックイディオムなどの一般的だが疑わしいコーディングイディオムが多数存在します。そのようなイディオムのほとんどは既存のセマンティクスでは無効であり、提案されたセマンティクス。」







ダークサイド



そして、そうであったように、これらの考慮事項はすべて見えています。 しかし、この問題には別の暗い側面があります。 より実用的な他の人々がいます。 彼らには独自の標準的な答えがあります。リスコフの原理などに従って、ソリッドで実行する開発者は単なる理論家です。 実際には、これはそうではなく、実際、シングルトーンが必要です。 このため、彼らには特別な哲学があります。 反哲学。







グローバルなステータスはどこにでもあります



主題領域自体でグローバルな状態が発生しないハロワールドまたは理論的な図ではないシステムを思い付くのは困難です。







少なくとも、グローバル変数は、私たち全員が住んでいる現実の世界です。 何らかの種類のコンピューターゲームMMORPGがある場合、それを記述すると、ゲームの単一の仮想世界もグローバルな状態になります。 別の人生と別の世界はありません。







よりローカルで、システムに単一のデータベースがあり、これがサブジェクト領域の一部である場合、多くの場合、その一意性にアタッチすることは理にかなっています。 そうしないと、適用された問題を解決する時間がなくなり、誰もが無数のデータベースの制御システムの作成を開始します。







ここでのテストの順序に関する引数も機能しません。実行中に、最初にベースのみを上げてから(ベースに対してテストを実行し)、次にアプリケーションコードを上げる必要があることは明らかです。 ベースの前にコードを上げると、すべてが落ちます。 私が見たプロジェクトのほとんどは、コードの前にデータベースを明示的に起動し、実際の問題はまったく見られませんでした。







「それだけで機能する」は明示的よりも優れている



最近のソフトウェアプロジェクトは非常に複雑です。 たぶん、これらは最も構造的に複雑なものであり、人類がその全歴史の中で行ってきたことのすべてです。







そして遅かれ早かれ、あなたのプロジェクトには、数千のクラス、外部ライブラリへの数百、数千の依存関係があります。 ある時点から、それらを手動で制御することはできません; Mavenのようなスマートビルドシステムが表示されます。 私が覚えている限りでは、Mavenは、Turbine Webフレームワークでプロジェクトを構築するときに開発者が出会った恐怖から現れました。







遅かれ早かれ、システムが理解不能になりつつあることに気付くでしょう。 その複雑さは、それが最も重要な重要な建築家であっても、一人の人間の脳に収まるには大きすぎます。 そして、内部接続、エラーの表示と維持、自動データフローなどについて考える自動化を探し始めます。







明らかに、そのようなシステムは主に魔法で構成されています。 そして、この場合、魔法は逃げ出すものではありません。 それどころか、努力する価値はあります。 しかし、それは良い、高品質、信頼できる魔法でなければなりません。







ハードはソフトよりも優れています



プロジェクトが大規模で理解しにくい場合、直接ハードリンクを使用するとコードが理解しやすくなります。 エラーが発生した場合、発生元の正確な場所はスタックトレースになります。 コードの構造を反映する非常に単純なグラフを作成する機会があります。 これをキューベースのコードの非常に弱いコヒーレンスと比較してください。システムのある場所で発生するエラーを実際にキューの反対側または複数のキューで検索する必要がある場合、そのような検索には数時間かかる場合があります。







テストに関して。 これが実際にどのように見えるかを見ると、多くのプロジェクトでは、テストはまったく行われないか、非常に切り捨てられた形式で行われます。 プロジェクトには数千のクラスを含めることができますが、テストは数十個しかありません。 そして、このわずかな量のために、システムを特別な方法で書き直して心配することはまったく意味がありません。 これは、シングルトーンだけでなく、一般的に適用されます-実際のフルスケールテストには、多くの追加条件が伴います。 実際には、テスタビリティを最前線に置くことは常に良い考えではありません。







Javaの仕様



はい、シングルトンのスペルは見苦しいです。 しかし、IDEではalwaysいクラスのテンプレートをいつでも作成でき、この厄介なコードを手作業で完全に記述することを忘れることができます。 彼らが言うように、闇は若者の友です。







解決策



ですから、私たちは真の対立の危機にonしていました:シングルトン(実際にはグローバルな状態、シングルトンと呼ぶ)を望む人もいれば、これに強く反対する人もいます。







素晴らしい解決策は、本物のシングルトンから喫煙者のシグトンに切り替えることです。 春のシングルトンビーンズ。 重要な点: コンポーネントスコープの注釈(SCOPE_SINGLETON)を使用して、一部のクラスをシングルトーンとしてマークします。







 import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) public class Greeter { public String hello() { return "Hello World!"; } }
      
      





次に、フィールドを作成できる場所であればどこでも@Autowiredとしてマークし、アプリケーションを起動すると、必要なインスタンスがこのフィールドに表示されます。







 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloWorldController { @Autowired Greeter greeter; @RequestMapping(path = "/") public String home() { return greeter.hello(); } }
      
      





このオプションは、上記のすべての問題を解決することに注意してください。









まとめ



シングルトンの問題は長い間解決されてきました。 まだ知らない人がいるのは驚くべきことです。 ソリューションは、Springおよびその他の反転制御システムと依存性注入です。 シングルトーンを作成する必要はありません。シングルトーンを書く人を憎む必要はありません。春に翻訳し、春の宗教に変換する必要があります。







その他



そして、あなたはビデオを見ただけでなく、最後まで読んだからです。 私のコンテンツを吸収してくれてありがとう、私にこの大きな名誉を与えてくれました。 (まじめに)そして今必要なもの:この記事にコメントを残してください、 HabréJavaハブ、JUG.ru友人のブログを購読してください。 。







さようなら!














All Articles