設計テンプレート「矛盾の検証を備えたミニスクリプト」

この記事では、コードの開発と操作をより明確にするために実際に試した自分の開発について説明します。



過去数年間、私は大規模なプロジェクトで働いていて、完全なコード難読化につながる特定のパターンにつまずきました。 約100人のチームによって20年間開発されてきたコードは、名義のないコードとはほとんど言えません。 それどころか、何千万行ものあらゆる善悪のテクニック、巧妙なアイデア、トリック、パッチ、クイックコピーペーストなどの山です...



画像






私が働いている組織はビジネスプロセスを自動化します。これは通常、データベースの保守に関連しています。 規範に従って仕事をするのが慣習です-最初にビジネス分析を行い、スマートTKをコンパイルし、コードを書き、テストを行い、短時間で多くのアクティビティを行います。 合理的と思われる主な動機は、「責任を分かち合いましょう」、「安全にしましょう」などです。 これらの管理手法はすべて、さまざまなコースで熱心に教えられており、多くの誇大広告とオームリアントが約束されています。 読者がすでに触れられたり注がれたりしないことがある流行の言葉に既に精通していることを願っています。 しかし、問題はそれらについてではなく、プログラマーがどのようにそれらと共存できるかについてです。



さらに、「ビジネスロジック」と「厳密なロジック」の違いを説明しようと思います。これらは、何らかの理由で十分な注意を払っていません。 ビジネスロジックを必死に使用した結果、数百年にわたって数学者や哲学者が戦ってきたロジックだけが苦しんでいます。 そして、実際の論理が苦しむと、これに伴い、初めてのパフォーマー-技術者が苦しみ、絶望から不条理なものを作り始め、ボスだけがそれを取り除くことができます。 そして、ブーメランで苦しみは「明るいスーパービジネスアイデア」のソースに戻り、他のさらに「明るいスーパービジネスアイデア」を思い付くか、最終的には他の人が通りで認識して指を向けないように偽のひげと暗い眼鏡をかけます。



職場で絶えず遭遇する特殊効果:



  1. サブジェクト領域は、プログラマーにとってはほとんど知られておらず、さらに明確に定式化されていません。
  2. 顧客は相反する要求を提示する場合があり、きれいな水の中に入れると、忍耐と対立が失われます。
  3. 請負業者は、ToRを完了し、テストに合格し、ビジネスからの時間とプレッシャーの不足でコードを戦闘に送信しようとします。 あなたが理解するためにあなたの頭を壊すので、少数の人々が気にしないしばらくした後のソリューションの美しさ。


正しいロジックを使用すると、矛盾がないか、矛盾がタイムリーに特定されます。 少なくとも私の技術的な心はそれを信じています。 しかし、プログラマーが望むように顧客に考えさせたり話したりさせることは難しいので、ソフトウェアレベルで建設的な妥協を模索します。



詳細を見て、簡単な例を分析します。 イマジネーションをオンにして、契約でベースを維持するとします。 データベースに、タイプ1とタイプ2の物理契約を入れます。 個人および法人向け。 上記から、TK 1の要件は、契約が発効するときに“ 1 1”



ます“ 1 1”



という言葉でプログラマーにダンプされ“ 1 1”







プログラマはそのようなコード番号1を作成します。



 if( doctype==1 ){ do_something1; }
      
      





しばらくして、TK 2から別の要件が引き下げられます: “ . 2”



2 “ . 2”



も、その発効時に。 しかし、問題は、古いプログラマーがすでに別の方向に波及しており、TK 2がすべてのニュアンスにうまく入らなかった別のプログラマーに既に割り当てられているため、コード番号2も簡単な方法で記述していることです。



 if( clienttype==ORGANIZATION ){ do_something2; }
      
      





次に、ビジネスロジックから実際のロジックに移行し、問題の原因を明確にする組み合わせのマトリックスを描きます。



表1

合法 顔

物理的な 顔
契約の種類1 do_something1

do_something2
do_something1
契約の種類2 do_something2


4つのセルを取得し、3/4のケースでプログラムが問題なく機能することを確認します。 また、衝突が発生するのは1つの場合のみです。両方のアクションが実行されます。 良くも悪くも、条件によって異なります。 時々それは良いこともあれば悪いこともありますが、私はコントロールしたいと思います。



より複雑な場合、より多くのタイプがある場合(表2を参照)、「すべてのタイプの契約」または「すべてのタイプの顧客」の悪名高い一般化は、組み合わせテーブルの行または列のように見えます。 そして、交差点で衝突が形成されます。 表2では、9つのケースのうち1つで衝突が発生しています。 プロジェクトが大きくなると、リストも大きくなり、干し草の山から針を見つけるのが難しくなります。 私は野外でのゴーファーについてのジョークを思い出します:「あなたは衝突を見ますか? いいえ、表示されません。 しかし、彼女はそうです!」



表2
顧客タイプ1 顧客タイプ2 顧客タイプ3
契約の種類1 do_something1

do_something2
do_something1 do_something1
契約の種類2 do_something2
契約の種類3 do_something2


プロジェクトが複雑になればなるほど、このマトリックスは大きくなり、時間とともに成長します。 したがって、分析を明確かつ正直にするために、別のタイプ-現在未知の「新しいタイプ」を追加する価値があります。 将来の世代は確かにそれに直面するでしょう、そして、それが意味することは、たぶん、単一のテレパスが告げないということです。



表3
顧客タイプ1 顧客タイプ2 顧客タイプ3 新しいタイプ

顧客

可能

将来的に
契約の種類1 do_something1

do_something2
do_something1 do_something1
契約の種類2 do_something2
契約の種類3 do_something2
新しいタイプ

合意

可能

将来的に


適切な組み合わせの描画の後、コードを記述するための素朴なアプローチの方法論的な欠陥が明らかになります。 上記の2行のプログラムが、困難な状況でビジネスにどのように干渉するかを自分で理解できます。



単純なコードには、次の質問に対する答えがありません。



  1. 新しいタイプに対して何をすべきか? 古いアルゴリズムに適合する保証は何ですか? 不慣れな状況にプログラムはどのように対応する必要がありますか?
  2. action1とaction2が相互に排他的な場合の対処方法
  3. 矛盾のないように、主題分野の知識を維持し、TKを定式化する方法は?


私がすでに記事[リンク]で強調しようとした最初の質問。 簡単に言えば、タイプリストをコードに導入することを提案しました。突然、新しいタイプがサブルーチンに入った場合、それは新しいタイプの出現を処理して通知する権利を持っています。 ちなみに、私はプロジェクトでこの手法もテストしましたが、実を結び、不確実な状況での運用プロセスを明確にしました。 (更新:防御的プログラミングには受信が存在します)



次に、2番目と3番目の質問-自動モードでタイムリーな矛盾を判断する方法を強調します。 結局、プロジェクトが数百万行を超えた場合、古いコードを台無しにしないように新しいコードを追加することは困難です。 実際、特定のスマートコンテナをビジネスオブジェクトに添付して、すべての要件を入力することを提案します。 そして、このコンテナは、TKの新しいアイテムが古いアイテムとどれだけうまくいくかをチェックします。 つまり、技術的なタスクの新しいポイントが到着すると、プログラマは組み込みのビジネスロジックを維持しながら、「来たとおりに」それをプログラミング言語に愚かにシフトします。 結果のコードとTKを見ると、多くの労力なしでそれらがどのように接続されているかが明確になるはずです。 次に、コードをスマートコンテナーに配置します。スマートコンテナーは、ビジネスロジックと厳密なロジックの間のリンクです。 プログラムで可能な限り、読者を裁判にかけます。 次に、自分の決定について説明します。



これを行うには、まず、条件の計算とアクション自体を分離することを提案します。 つまり、do_somethingとは別にifを拡散します。 条件を計算するとき、データベースまたはグローバル変数に変更を加えることは禁止されています。 関数型プログラミングと純粋なロジックにより近いです。 外部コンテキストでは何も変化せず、論理式のみが計算されます。 TKの条件とプログラムアクションの間に、よりソフトなリンクが導入されています。 最初の段階では、コンテナがテキストを形成します-人とプログラムの両方が簡単に解釈できます。



最初の段階の出口で、コンテナは以下を生成します。



  1. 小さなテキストまたは単純なデータ構造の形式のメインミニスクリプト。
  2. テキスト形式の追加の警告と推奨事項。
  3. テキストまたは例外の形式のエラーは、希望に応じてスローされます。


ミニシナリオ形成スキームは次のようになります。



画像



図1.第1段階のスキーム



ミニスクリプトが形成されると、ToRの大きな一般化されたテキストは、現在の状態の特定のビジネスオブジェクト(契約、クライアント、ドキュメントなど)に適したコンパクトで読みやすいテキストに縮小されることがわかります。 このテキストは、データベースおよび基本操作の特定のアクションにすでに近いですが、それでもかなり抽象的であり、データベースまたは環境に依存しません。 さらに、次の段階では、スクリプトに従ってデータベースの変更が行われる前に、多くの有用なことを実行できます。



予想されるプラスはどれですか:



  1. このコンテナはデータを変更せず、テキストのみを返すため、好きなように使用できます。 何も変更することを恐れることなく、データベース全体で実行できます。 ミニスクリプトの新しいテキストと古いテキストを比較することにより、回帰テストを実行できます。 予測を行うことができます-特定のケースでプログラムが何をするか。

  2. 弱い結合の有用な原理は、純粋なロジックと純粋な変更が異なるサブプログラムに持ち込まれたときに実現されます。

  3. 機能を追加する場合、構成を通じていくつかのブロックをオンまたはオフにできます。 戦闘にアクセスできない場合は特に重要ですが、バグのあるピースを無効にする必要があります。

  4. テキストメッセージは母国語で作成できるため、テスター、ビジネスアナリスト、ユーザーなど、他の専門分野の専門家の理解が深まります。

  5. 私が伝えたい最も重要なことは、矛盾の自動制御です。これについては、以下で説明します。



短所は何ですか:



  1. 新しいものと古いものの両方のすべての条件を計算する必要があります。つまり、時間の経過とともに遅くなりますが、正しく動作します。 私たちは時期尚早の最適化から離れ、ドナルド・クヌースの言葉を思い出してください。「時期尚早の最適化はすべての悪の根源です」。

  2. プログラミング言語には、パターンに従ってパターンを正しく記述することを強制する簡潔で美しい構造はありません。 潜在的に、あなたはまだパターンに逆らって、矛盾するはずのロジックを導入すべきではありません。 つまり、特定のルールに従って特定の場所に新しい参照条件を追加するには、開発者からの規律が必要です。



実装の説明に進みます。 入力パラメーターは次のとおりです(図1):



  1. ビジネスオブジェクトを識別するデータ。 最も単純なケースでは、データベース内のJavaオブジェクトまたはオブジェクトIDへの単なる参照になります。 しかし、この関数は、オブジェクトへの直接リンクがない場所など、非常に異なる場所から呼び出すことができるため、実際にはユニバーサルパラメーターを作成し、最初のブロック(図1)でオブジェクトを検索しました。

  2. 2番目のパラメーターはコマンドです。 たとえば、「set boo。 アカウント「または」「次のステータスを設定」など チームは、柔軟性を最適化し、向上させるように設計されています。 現在のオブジェクトの完全なミニスクリプトを常に提供し、ミニスクリプトプロセッサが状況に応じて実行する必要があるものを決定したため、実際には必要ありませんでした。



次のブロックでは、最適化とロギングなしで、すべてのTKのすべての条件が計算されます。 テスターのコメントにすばやく応答するために、テストサーバーでのみログを使用しました。 ログにTKから送られてきたフレーズを書いたので、フライトを分析するときに参照するものがありました。 つまり、このアプローチを使用しました。



  bool1 = contract.type_id == 1; log(“  1  =1 ” + bool1.toString()); if( bool1 ){ add_miniscript(“ ”,“50/**/); } //key value bool2 = contract.client.type == ORGANIZATION;; log(“  2    ” + bool2.toString()); if( bool2 ){ add_miniscript(“ ”,“66”/**/); }//key value
      
      





矛盾と衝突をどのように正確に検出するか-おそらく多くはすでに推測しています。 連想配列key = valueが役に立ちます。 キーはコマンドであり、値はそのパラメーターです。 特に値が異なる場合、属性の値を複数回設定することは、矛盾の悪名高い例です。 以下のコードに詳細があります。



アプリケーションインフラストラクチャは次のとおりです。



画像

図2



遭遇したすべてのニュアンスをまだ公開していません。 OOPを使用せずに、この動作パターンの最初のバージョンをOracle PL / SQLに実装しました。 つまり、パターンは普遍的であり、OOPと手続き型の両方に適用可能であると考えることができます。 15ポイントで構成された最初の難しいTKで、最初の1週間と6か月後の4つの矛盾を明らかにしました。これは、特定のケースで自分の言葉がこうなるとさえ思わないアナリストを驚かせました。



読むことに飽きていない人のために、実行できるJava実装を以下に説明します。検出された衝突がコンソールに表示されます。 ミニスクリプトは、スクリプトの要素({key、value}のペアとコメント)が追加される順序付きリストの形式で実装されます。 このリストが選択されるのは、実際にはいくつかのキーで衝突を許可する必要があるためです。 これを行うために、衝突処理をオン/オフできるコードの一部があります。 コード内の詳細なコメント。 開発環境にコピーして実行すると動作するはずです。



ファイル:testMiniscript.java



 package test; import java.util.ArrayList; import java.util.List; import java.util.Optional; //   -,       . interface IMiniScript{ MiniScript GetMiniscript(String command) throws MiniScriptExcept; //   void ExecuteMiniScript(MiniScript ms) throws MiniScriptExcept; //   } //   class MiniScriptItem{ private final String key; //       private final String parameter; //  .  private final String comment; //  ,     public MiniScriptItem(String key, String parameter, String comment) { this.key = key; this.parameter = parameter; this.comment=comment; } public String getKey() { return key; } public String getParameter() { return parameter; } public String getComment() { return comment; } @Override public String toString() { return "MiniScriptItem{" + "key=" + key + ", parameter=" + parameter + ", comment=" + comment + '}'; } }// MiniScriptItem class MiniScriptExcept extends Exception { MiniScriptExcept(String string) { super(string); } } //    ,     ,       class MiniScript { //  List   HashMap,       ,   allowDublicate(key) List<MiniScriptItem> miniScriptItemList = new ArrayList<MiniScriptItem>(); //   .  6  . 1 void add(String pkey, String pparameter, String pcomment) throws MiniScriptExcept{ if(allowDublicate(pkey)){ //   ,    miniScriptItemList.add(new MiniScriptItem(pkey, pparameter,pcomment)); }else{ //   ,   MiniScriptItem conflict=null ; for (MiniScriptItem miniScriptItem : miniScriptItemList) { if(miniScriptItem.getKey().equals(pkey)){ conflict= miniScriptItem; } } if(conflict!=null){ //   throw new MiniScriptExcept("  . " +System.getProperty("line.separator") +"key="+conflict.getKey()+" parameter=" +conflict.getParameter()+" comment="+conflict.getComment() +System.getProperty("line.separator") +"key="+pkey+" parameter=" +pparameter+" comment="+pcomment );//throw }else{ //key    ,   miniScriptItemList.add(new MiniScriptItem(pkey, pparameter,pcomment)); } } } //    ,   . //     -   override   boolean allowDublicate(String key){ //   ,     ,   2 .           // if(key.equals(" ")){ // return true; // } return false; } @Override public String toString() { return "MiniScript{" + "miniScriptItemList=" + miniScriptItemList + '}'; } }//MiniScript // C    c   - class Contract implements IMiniScript{ int type=1; String clienttype="."; //   1  . //     1 ",  ", //         . //   ""   @Override public MiniScript GetMiniscript(String command) throws MiniScriptExcept{ MiniScript ms = new MiniScript(); //     -  . //   -  . if(command.equals("   ")){ //  2  . 1 “    1” if(type==1){ ms.add(" ", "50 ", "  1"); } //  3  . 1 “    2” if(clienttype.equals(".")){ ms.add(" ", "66 ","  2"); } // 5  . 1 “    ” //<<<<         >>>> //<<<<         >>>> }else{ //    //        throw new MiniScriptExcept("  "+command); } return ms; } @Override public void ExecuteMiniScript(MiniScript ms) throws MiniScriptExcept { List<MiniScriptItem> items = ms.miniScriptItemList; for (MiniScriptItem item : items) { if(item.getKey().equals(" ")){ //  System.err.println("      "+item.getParameter()+" "+item.getComment()); }else{ throw new MiniScriptExcept("  "+item.getKey()); } } } }// Contract public class testMiniscript { public static void main(String[] args) throws MiniScriptExcept { //  2   Contract c = new Contract(); c.type=1; c.clienttype="."; //   MiniScript ms=c.GetMiniscript("   "); //      , // ,    -     //    c.ExecuteMiniScript(ms); System.err.println(" " + ms.toString()); } }
      
      





これで私は投稿を終えたいと思います、私はコメントとこの分野での私自身の開発に喜んでいます。 資料が役に立てば幸いです。



PS:一部の読者は、なぜ私はそれをパターンではなく、テクニックではなく、メソッドでも、パターンでも、テクノロジーでもない何かと呼んだのだろうと思うかもしれません。 名前に厳密な違いはないと思うので、何かに立ち止まって何らかの形で名前を付ける必要があります。 実際的な利点を評価しましょう。



ウィキペディアからの追加情報:

業務ルール管理システム

IoC



リバコフD.A.

博士号、2017年11月



All Articles