クラスデザむン䜕が良いですか





投皿者 Denis Tsyplakov 、゜リュヌションアヌキテクト、DataArt



䜕幎もの間、プログラマヌは時々同じ間違いを繰り返すこずを発芋したした。 残念ながら、開発の理論的偎面に関する本はそれらを回避するのに圹立ちたせん。通垞、本には具䜓的で実甚的なアドバむスがありたせん。 そしお、私も理由を掚枬したす...



たずえば、 ロギングやクラス蚭蚈に関しお最初に頭に浮かぶ掚奚事項は非垞に単玔です。 しかし、経隓では、それだけでは十分ではないこずが瀺されおいたす。 この堎合のクラスの蚭蚈は良い䟋です-誰もがこの質問を独自の方法で芋るずいう事実から生じる氞遠の頭痛。 したがっお、基本的なヒントを1぀の蚘事にたずめるこずで、倚くの兞型的な問題を回避し、最も重芁なこずずしお、同僚をそこから救うこずにしたした。 いく぀かの原則があなたにずっお平凡に思える堎合それらは本圓に平凡だからです-それで、それらはすでにあなたの皮質䞋に萜ち着いおおり、あなたのチヌムは祝犏されたす。



私は予玄をしたす。実際、単玔化のためだけにクラスに焊点を圓おたす。 アプリケヌションの機胜やその他の構成芁玠に぀いおもほが同じこずが蚀えたす。

アプリケヌションが機胜しおタスクを実行する堎合、その蚭蚈は良奜です。 かどうか アプリケヌションの目的関数に䟝存したす。 展瀺䌚で䞀床衚瀺する必芁があるモバむルアプリケヌションに非垞に適しおいるものは、銀行が長幎開発しおいる取匕プラットフォヌムには適さない可胜性がありたす。 ある皋床たで、この質問に察する答えはSOLID原則ず呌ぶこずができたすが、それはあたりにも䞀般的です-同僚ずの䌚話で参照できる、より具䜓的な指瀺が必芁です。



察象アプリケヌション



普遍的な答えはないので、範囲を狭めるこずを提案したす。 HTTPたたは別のむンタヌフェむスを介しお芁求を受け入れ、それらの䞊にいく぀かのロゞックを実装し、チェヌン内の次のサヌビスに芁求を行うか、受信したデヌタをどこかに栌玍する暙準のビゞネスアプリケヌションを䜜成しおいるずしたす。 簡単にするために、Spring IoCフレヌムワヌクを䜿甚しおいるず仮定したす。これは珟圚非垞に䞀般的であり、残りのフレヌムワヌクはかなり䌌おいるためです。 そのようなアプリケヌションに぀いお䜕を蚀えたすか





最適化基準



この堎合、私たちにずっお䜕が重芁ですか



プロゞェクトコヌドは、ビゞネスで数幎、おそらく10幎以䞊䜿甚される可胜性がありたす。



コヌドは、互いになじみのない耇数の開発者によっお数回修正されたす。

数幎埌には、開発者が新しいLibXYZラむブラリたたはFrABCフレヌムワヌクを䜿甚したくなる可胜性がありたす。



ある時点で、コヌドの䞀郚たたはプロゞェクト党䜓を別のプロゞェクトのコヌドベヌスずマヌゞできたす。



マネヌゞャヌの䞭で、そのような問題はドキュメントの助けを借りお解決されるこずが䞀般的に受け入れられおいたす。 もちろん、ドキュメントは䟿利で䟿利です。プロゞェクトで䜜業を開始するず、5枚のオヌプンチケットがかかっおいるので、プロゞェクトマネヌゞャヌから進捗状況を尋ねられ、玄150冊を読んで芚えおください。優秀な䜜家からはほど遠い文章のペヌゞ。 もちろん、プロゞェクトに泚ぐのに数日、あるいは数週間もありたしたが、単玔な算術挔算を䜿甚する堎合は、䞀方で5,000,000バむトのコヌド、もう䞀方では、たずえば50劎働時間です。 平均するず、1時間あたり100 KBのコヌドを挿入する必芁がありたした。 そしお、ここではすべおがコヌドの品質に倧きく䟝存したす。 きれいな堎合組み立おが簡単で、適切に構造化され、予枬可胜である堎合、プロゞェクトに泚ぐこずは、それほど苊痛の少ないプロセスのようです。 これで最埌の圹割は、クラスの蚭蚈ではありたせん。 最埌から遠い。



クラスのデザむンから欲しいもの



䞊蚘のすべおから、䞀般的なアヌキテクチャ、技術スタック、開発プロセスなどに぀いお倚くの興味深い結論を匕き出すこずができたす。しかし、最初からクラス蚭蚈に぀いお話すこずにしたした。それに関しお先に述べたこずから孊べる有甚なこずを芋おみたしょう。





実甚的な掚奚事項



垌望を定匏化しお、目暙を達成するための具䜓的な手順を抂説できたす。



静的メ゜ッド



りォヌムアップずしお、比范的単玔なルヌルから始めたす。 䜿甚するラむブラリのいずれかの操䜜に必芁でない限り、静的メ゜ッドを䜜成しないでくださいたずえば、デヌタ型のシリアラむザヌを䜜成する必芁がありたす。



原則ずしお、静的メ゜ッドを䜿甚しおも問題はありたせん。 メ゜ッドの動䜜がそのパラメヌタに完党に䟝存しおいる堎合、実際に静的にしないのはなぜですか。 ただし、アプリケヌションのコンポヌネントをバむンドするSpring IoCを䜿甚するずいう事実を考慮する必芁がありたす。 Spring IoCは、BeanBeanずそのスコヌプScopeの抂念を扱いたす。 このアプロヌチは、クラスにグルヌプ化された静的メ゜ッドず組み合わせるこずができたすが、このアプリケヌションを理解し、その䞭の䜕かを倉曎するこずさえできたすたずえば、メ゜ッドたたはクラスにグロヌバルパラメヌタヌを枡す必芁がある堎合。



同時に、IoCビンず比范した静的メ゜ッドは、メ゜ッド呌び出しの速床においお非垞にわずかな利点をもたらしたす。 そしおこれで、おそらく利点が終わりたす。



異なるクラス間で倚数の超高速呌び出しを必芁ずするビゞネス機胜を構築しおいない堎合は、静的メ゜ッドを䜿甚しない方が良いでしょう。



ここで、読者は「しかし、StringUtilsクラスずIOUtilsクラスはどうなのか」ず尋ねるかもしれたせん。実際、Javaの䞖界には䌝統がありたす。 しかし、この䌝統は私にはむしろ苔むしたようです。 もちろん、それに埓えば、倧きな害は予想されたせん。すべおのJavaプログラマヌが慣れおいたす。 しかし、そのような儀匏的な行動には意味がありたせん。 䞀方では、StringUtils Beanを䜜成し、他方では、Beanおよびすべおの補助メ゜ッドを静的にしないのであれば、静的な傘クラスStockTradingUtilsおよびBlockChainUtilsをすでに䜜成したしょう。 静的メ゜ッドにロゞックを配眮し始めお、境界線を描いお停止するのは困難です。 始めないでください。



最埌に、Java 11では、開発者をプロゞェクト間で䜕十幎もさたよっおいた倚くのヘルパヌメ゜ッドが、暙準ラむブラリの䞀郚になるか、たずえばGoogle Guavaのラむブラリにマヌゞされたこずを忘れないでください。



アトミックでコンパクトなクラス契玄



すべおの゜フトりェアシステムの開発に適甚される簡単なルヌルがありたす。 任意のクラスを芋るず、長い発掘調査に頌るこずなく、このクラスが䜕をするのかを迅速か぀コンパクトに説明できるはずです。 説明を1぀の段萜に収めるこずが䞍可胜な堎合ただし、必ずしも1぀の文で衚珟されるずは限りたせん、このクラスをいく぀かのアトミッククラスに分けお考える䟡倀があるかもしれたせん。 たずえば、「ディスク䞊のテキストファむルを怜玢し、それぞれの文字Zの数をカりントする」クラス-「ディスク䞊の怜玢」+「文字の数をカりントする」分解の良い候補です。



䞀方、それぞれが1぀のアクション甚に蚭蚈されたクラスを小さくしすぎないでください。 しかし、クラスはどのサむズにする必芁がありたすか 基本的なルヌルは次のずおりです。





このルヌルが重芁なのはなぜですか





すべおが十分にきめ现かであるこずを確認する方法は 同僚に5分5分䞎えるよう頌んでください。 珟圚䜜業䞭のアプリケヌションの䞀郚を担いたす。 各クラスに぀いお、このクラスが正確に䜕をするかを同僚に説明したす。 5分以内に収たらない堎合、たたはこのクラスが必芁な理由を同僚が理解できない堎合は、おそらく䜕かを倉曎する必芁がありたす。 たあ、たたは倉曎せずに、別の同僚ず実隓をやり盎しおください。



クラスの䟝存関係



ZIPアヌカむブにパックされたPDFファむルのリンクされたテキストセクションを100バむトより長く遞択し、それらをデヌタベヌスに保存する必芁があるずしたす。 このような堎合の䞀般的なアンチパタヌンは次のようになりたす。





䞀方では、すべおが論理的に芋えたす。チェヌン内の次のクラスず盎接呌ばれる受信デヌタ。 ただし、同時に、チェヌンの最䞊䜍にあるクラスのコントラクトは、その背埌にあるチェヌンに含たれるすべおのクラスのコントラクトず䟝存関係に混圚したす。 これらのクラスをアトミックか぀盞互に独立させ、これら3぀のクラスを盞互に接続しお凊理ロゞックを実際に実装する別のクラスを䜜成する方がはるかに正確です。



それをしない方法







ここで䜕が間違っおいたすか ZIPファむルを凊理するクラスは、PDFを凊理するクラスにデヌタを枡し、次に、デヌタベヌスを凊理するクラスにデヌタを枡したす。 これは、結果ずしお、䜕らかの理由でZIPで機胜するクラスがデヌタベヌスで機胜するクラスに䟝存するこずを意味したす。 さらに、凊理ロゞックは3぀のクラスに分散しおいるため、それを理解するには、3぀のクラスすべおを調べる必芁がありたす。 REST呌び出しを介しおサヌドパヌティのサヌビスに枡すためにPDFから取埗したテキストの段萜が必芁な堎合はどうなりたすか PDFで動䜜するクラスを倉曎する必芁がありたす。たた、その䞭でRESTを䜿甚する必芁がありたす。



方法







ここには4぀のクラスがありたす。





2019幎のJavaには少なくずも2぀の良い点があるこずを匷調したす

良いファむルずすべおの段萜の完党なリストをメモリ内のオブゞェクトずしお転送しない方法。 これは



  1. Java Stream API
  2. コヌルバック ぀たり、ビゞネス関数を含むクラスはデヌタを盎接転送したせんが、ZIP Extractorを䜿甚したすここにコヌルバックがありたす。ZIPファむルでPDFファむルを探し、各ファむルのInputStreamを䜜成し、転送されたコヌルバックを呌び出したす。


暗黙の動䜜



以前は誰も解決しおいなかったたったく新しい問題を解決しようずせず、他の開発者がすでに数癟たたは数十䞇回行ったこずがある堎合、チヌムメンバヌ党員が゜リュヌションの埪環的な耇雑さずリ゜ヌス集玄性に䞀定の期埅を抱いおいる。 たずえば、ファむル内で文字zで始たるすべおの単語を怜玢する必芁がある堎合、これはディスクからブロック単䜍でファむルを1回だけ連続しお読み取るこずです。 ぀たり、 https//gist.github.com/jboner/2841832に焊点を合わせた堎合、そのような操䜜には1 MBあたり数マむクロ秒かかりたす。おそらく、プログラミング環境ずシステム負荷によっおは、数十たたは100マむクロ秒にもなりたすが、䞀秒でもありたせん。 数十キロバむトのメモリが必芁になり結果をどうするかずいう質問は省きたす。これは別のクラスの関心事です、コヌドはおそらく1画面皋床かかりたす。 同時に、他のシステムリ゜ヌスが䜿甚されないこずが予想されたす。 ぀たり、コヌドはスレッドを䜜成せず、デヌタをディスクに曞き蟌み、ネットワヌクを介しおパケットを送信し、デヌタベヌスにデヌタを保存したせん。



これはメ゜ッド呌び出しの通垞の期埅です



zWordFinder.findZWords(inputStream). ...
      
      





たずえば、単語をzではなくzに分類するなど、䜕らかの理由でクラスのコヌドがこれらの芁件を満たしおいない堎合、毎回RESTメ゜ッドを呌び出す必芁がありたすこれが必芁な理由はわかりたせんが、これを想像しおみたしょうクラスコントラクトには非垞に慎重に蚘述する必芁がありたす。たた、メ゜ッドの名前が、参照するメ゜ッドがどこかで実行されおいるこずを瀺しおいる堎合は非垞に䟿利です。



暗黙的な動䜜の合理的な理由がない堎合は、クラスを曞き換えたす。



メ゜ッドの耇雑さずリ゜ヌス集玄床ぞの期埅を理解する方法は 次の簡単な方法のいずれかに頌る必芁がありたす。



  1. 経隓を積むず、かなり広い芖野が広がりたす。
  2. 同僚に尋ねる-これはい぀でもできたす。
  3. 開発を開始する前に、チヌムメンバヌず実装蚈画に぀いお話し合いたす。
  4. 次の質問を自問しおください。「しかし、この方法では冗長なリ゜ヌスを䜿いすぎないのですか」通垞、これで十分です。


最適化にも関䞎する必芁はありたせん。クラス100,000で䜿甚するずきに100バむトを節玄しおも、ほずんどのアプリケヌションではあたり意味がありたせん。



このルヌルは、「゚ンゞニアリングに10 GBを必芁ずするアプリケヌションで10バむトのメモリを節玄するために1か月を費やすべきではない」などの質問に察する答えを隠し、オヌバヌ゚ンゞニアリングの豊かな䞖界ぞの窓を開きたす。 しかし、ここではこのトピックを䜜成したせん。 圌女は別の蚘事に倀したす。



暗黙的なメ゜ッド名



Javaプログラミングでは、珟圚、クラス名ずその動䜜に関する暗黙的な芏則がいく぀かありたす。 それらの倚くはありたせんが、それらを壊さない方が良いです。 私の頭に浮かぶものをリストしおみたす





䟋を挙げたしょう。 私は最近、アプリケヌション監査を行いたした。 䜜業のロゞックにより、コヌド内のどこかのアプリケヌションがRabbitMQキュヌをサブスクラむブするこずがわかりたす。 私はコヌドを歩いおいたす-この堎所が芋぀かりたせん。 私はりサギぞのアピヌルを盎接探しおおり、登り始めおいたす。サブスクリプションが実際に行われるビゞネスフロヌの堎所に行きたす-私は誓いたす。 コヌドでの衚瀺



  1. service.getQueueListenertickerNameメ゜ッドが呌び出されたす-返された結果は無芖されたす。 これは譊告するかもしれたせんが、メ゜ッドの結果が無芖されるようなコヌドは、アプリケヌション内の唯䞀のコヌドではありたせん。
  2. 内郚では、tickerNameのnullがチェックされ、別のgetQueueListenerByNametickerNameメ゜ッドが呌び出されたす。
  3. その䞭で、QueueListenerクラスのむンスタンスは、ティッカヌの名前によっおハッシュから取埗されそうでない堎合は䜜成されたす、getSubscriptionメ゜ッドが呌び出されたす。
  4. そしお今、getSubscriptionメ゜ッド内で、サブスクリプションが実際に行われたす。 そしお、それは3画面のサむズのメ゜ッドの途䞭で発生したす。


率盎に蚀っお-チェヌン党䜓を実行せず、泚意深い数十のコヌド画面を読むこずなく、サブスクリプションがどこにあるかを掚枬するこずは非珟実的でした。 メ゜ッドがsubscribeToQueueByTickertickerNameず呌ばれた堎合、時間を倧幅に節玄できたす。



ナヌティリティクラス



「Design PatternsElements of Reusable Object-Oriented Software1994」ずいう玠晎らしい本がありたすが、これは倚くの堎合、GOF䜜者の数では4人のギャングず呌ばれおいたす。 この本の有甚性は、䞻に、さたざたな囜の開発者にクラスデザむンテンプレヌトを蚘述するための単䞀の蚀語を提䟛したずいう事実にありたす。 珟圚、「クラスは1぀のむンスタンスにのみ存圚し、静的アクセスポむントを持っおいるこずが保蚌されおいる」の代わりに、「シングルトン」ず蚀うこずができたす。 同じ本は、脆匱な心に顕著な損害を匕き起こしたした。 この害は、フォヌラム「同僚、Webストアを䜜成する必芁があり、どのテンプレヌトから始める必芁があるかを教えおください」の1぀からの匕甚でよく説明されおいたす。 蚀い換えれば、䞀郚のプログラマヌは蚭蚈パタヌンを乱甚する傟向があり、1぀のクラスで管理できる堎合はい぀でも、「柔軟性を高めるため」に5぀たたは6぀を䞀床に䜜成したす。



抜象クラスファクトリたたはむンタヌフェむスよりも耇雑な別のパタヌンが必芁かどうかを刀断する方法 いく぀かの簡単な考慮事項がありたす。



  1. Springでアプリケヌションを䜜成しおいる堎合、99の時間は必芁ありたせん。 Springは、より高いレベルのビルディングブロックを提䟛したす。 圹に立぀ず思われる最倧倀は、抜象クラスです。
  2. ポむント1でもただ明確な答えが埗られない堎合は、各テンプレヌトがアプリケヌションの耇雑さを+1000ポむント瀺しおいるこずに泚意しおください。 テンプレヌトを䜿甚するメリットが、その害を䞊回るかどうかを慎重に分析したす。 メタファヌに目を向けるず、それぞれの薬が治癒するだけでなく、わずかに害を䞎えるこずを忘れないでください。 すべおの薬を䞀床に飲たないでください。




䞍芁な方法の良い䟋は、 こちらをご芧ください 。



おわりに



芁玄するず、最も基本的な掚奚事項がリストされおいるこずに泚意しおください。 私はそれらを蚘事の圢で䜜成するこずさえしたせん-それらはずおも明癜です。 しかし、過去1幎間で、これらの掚奚事項の倚くが違反されおいるアプリケヌションに頻繁に出くわしたした。 読みやすく保守しやすいシンプルなコヌドを曞きたしょう。



All Articles