10年の練習。 パート1:プログラムの作成

10年間、私はC ++で書いてきました。 最初の5年間は、コンピューターゲーム用の効果的なコードを書くことが私の仕事でしたが、産業施設の自動化に関するものであったため、主な要件は安定性でした。 効果的であると同時に安定した作業プログラムを作成するのに役立つ個人的な経験と実践的な経験を共有したいと思います。

画像



この資料は、初心者向けの最も一般的な実践ルールから、経験豊富なプログラマーに関連する特定の質問まで、いくつかの部分に分かれています。

最初の部分では、実際には最も基本的な質問に答えます。 一般にプログラム、特に複雑なプログラムを書く方法は? 最初からやり直さないように、最初に何をすべきですか? 最適なプログラム構造を作成する方法は?



同僚の皆さん、C ++で書いています。 原則として、これはプログラムが複雑であることを意味します。 いくつかは非常に複雑です。 プログラムが正常に機能するためには、作成者である私が、細部に至るまで、どのように機能するかを覚えておく必要があります。 完全に考え出すことができなかったのは保証されたバグだけなので、これは必要条件です。



抽象化のすべてのレベルで全体像を同時に念頭に置くことは不可能です。 したがって、私は複雑なシステムをより単純な部分に分割しています。 それらのそれぞれは、爪のようによく理解されており、明白です。 より複雑なものはすべて、より単純な要素から組み立てられます。 明らかに? もちろん! ただし、この規則を厳密に遵守する必要があります。



実用化されていない技術や要素を使用するプログラムを作成する場合、最初に練習を行います。 必要な部分を含む小さなコンソールプログラム。 青に変わるまで、どのように機能し、何が機能するのか、入力データの制限は何か、どの機能や落とし穴があるのか​​が明確になるまで、このスケッチを苦しめます。 はい、私は数百の研究のディレクトリ全体を持っています。 それぞれが最終的に独立したコードの断片(ほとんどの場合、クラスまたはクラスの束)になり、それをバッテリーとしてプログラムに挿入します。古いバージョンを取り出し、新しいものをスタックしました。



要素の「接着」は、それ自体がかなり複雑なメカニズムである場合があるため、個別の調査が必要です。 しかし、これは複雑なメカニズムに関しては十分ではありません。 私が紙に書くすべての複雑なアルゴリズム。 ロシア語では説明できないものをC ++で書くことは不可能です。 何かを言葉で表現すると、脳は落とし穴や矛盾に出くわします。 これらは、コードがすでに記述されている最後ではなく、最初に表示されます。 テキスト自体は洗練された、微妙なポイントが言及されている必要があります。 別のプラス:1年でプロジェクトに戻ることができ、これがなぜそのように行われるのかを覚えて数週間を費やす必要はありません。

顧客ごとに、ノートブックを作成しました。 それらには、航行中のフリゲートの周りの現実的な泡の作成から、熱い金属や酸の周りの狭い場所でのクレーンの最適な軌道の計算まで、すべての重要な瞬間が含まれています。 同様のタスクに遭遇した場合、ノートブックを見るだけです。 そこでは、取り消し線で囲まれたテキストと図の中で、10〜15分で、すべての機能を備えたアルゴリズム作成の全過程をメモリに再現します。 原則として、タスクは完全には繰り返されませんが、3〜4年後には何らかのアイデアが必要です。



明らかに? いいね! それを少し複雑にして、上で話した要素の内部を見てみましょう...



C ++は、C ++クラスが実際のオブジェクトの説明を頻繁に繰り返すという意味で非常に単純です(直接コピーの意味ではなく、名前の意味、機能と関係の一部、さらにC ++には合成補助クラスがあります) 。 実世界のオブジェクトが別の実世界のオブジェクト(1つだけ)であるか、それを含む場合、C ++はクラスの継承を適用​​します。 子孫オブジェクトに同じタイプの複数を含めることができる場合、子孫クラスにオブジェクトの包含を適用します。 同じクラスの振る舞いを別のクラスに分けます(これをミキシングクラスと呼びます)。 これらはすべてアランゴラブ[2]によってうまく描かれているので、見事に書かれたテキストを繰り返しません。 この単純なニーモニックルールを記憶し、マシンに適用する必要があると言います。



はるかに少ない標準的な問題は、クラスのメンバーおよびメンバー関数へのアクセス権の配布です。 もちろん、カプセル化については誰もが知っています。誰もが本を読みます。 これらすべてを実際にどうするか?



実際には、次のことが起こります。 センサーが接続されている実際のバンカーを記述するバンカークラスを作成しています。 バンカーはワークショップにまとめられ、これらすべてが美しいインターフェースに表示され、何らかの形で互いに、また人とやり取りします。

問題は、バンカーに関する内部情報を他のクラスにどれだけ公開したかです。 答えは、何もありません。 分かりますか? クラスのすべてのメンバーはプライベートです。 クラスの内部が何であるかを外部から知る必要はありません。 その理由は明らかです。クラス内で何かを変更し、変更のチェーンがコード全体に広がっていました。1秒前は、スイス時計のようにクリーンでデバッグされていました。

そのため、バンカーはその実装の詳細を公開しません。 同時に、彼はインターフェースに自分自身を表示し、コントロールのクリックを処理し、その仕組みの知識を必要とするすべての作業を実行します。 外側に開いているのは、クラスにこれまたはそのジョブを実行するように要求するメンバー関数です:インターフェイスで自分を表示し、マウスクリックを処理し、XMLで自分を保存します。



おそらくあなたは尋ねるでしょう:多分それを複雑にする価値はなかったので、クラスをよりオープンでフレンドリーにしてみませんか? 「まさか」と答えます。「それが理由です。」

2か月のプログラムが機能し、顧客からバンカーのリモートコントロールを依頼されました。 次に、インターネットからセルラーネットワークおよびシリアルポートまで、さまざまな通信チャネルを介したリモート制御が必要であり、通信チャネルを複製する必要があります。 時間が経つにつれて、プログラムは機能し、徐々にオペレーターのアクションログのリモート同期の必要性が明らかになります。 そして、数か月後、私はバンカーとログの状態を通信の悪い状態で同期させる必要があることを発見しました(例えば、ノイズの多いRS-485または長距離でのWi-Fi)。



私は何をしましたか? バンカークラスを複雑にしました。これは、ローカルでもリモートでも動作します。 GSM / Ethernet / RS-232設定を取得するコードを追加しました。 そして最も重要なのは、他のすべてが元のままであるということです。 制御アルゴリズムの微調整のすべての月は私に残っています! 同じことが雑誌にも当てはまりました。

少なくともバンカーの内側のキッチンから何かを引き出した場合、250 kBの制御コードからどのくらい書き直さなければならないか想像することさえできません。



繰り返しますが、重要な点を繰り返します。C++プログラムの構造は、Cとは正反対です。 構造と共通変数がありました。 ここには、ブラックボックスのオブジェクトがあります。 各オブジェクトはそれ自体が刈り取り機、スイス人、パイプ上の男です。

一方、クラスコード自体はシンプルである必要があります。 複雑な機能が必要な場合は、内部ヘルパーオブジェクトのクラスに含めることで実装するか、混合クラスを使用します(ただし、継承は包含よりも強力な結合形式であるため、より慎重に行います)。



get / setアクセスは、公開クラスのメンバーの少しベール化されたバージョンであることを思い出します。 このアプローチでは、私たちは途中ではありません。



オブジェクトと対話する正しい方法は、彼に1つまたは別のアクションを実行するように依頼することです。

データを要求する代わりに、オブジェクトに独自のアクションを実行するように依頼します。 これは、C ++での大規模プロジェクトの安定性に必要な条件です。 場合によっては、一部のアクションの実装は、単にクラスメンバーの値を返すことです(ルールを確認する例外)。



そして最後の1つ。 どんな構造でも、成長の可能性は限られています。 おそらく顧客は、クラス間の相互作用のインターフェースを変更する必要があるようなグローバルな変更を要求するでしょう。 さらに、クラスの構造を変更する必要がある場合があります。 しかし、これだけではありません。プログラムを実行するための客観的な時間枠があり、その間に新しいクラス構造を作成する必要性が明らかになります。



私は安心したい:これはすべて完全に正常です。 彼らはプログラムを使用します-それはプログラムが生きていることを意味し、そのため、その構造は変化して発展します。 プログラムが本当に良くなる前に、それはほぼ確実に数回書き換えられなければなりません(私の最も深刻なプログラムは通常2回または3回書き換えられます)。 このようなプログラムは優れた成長の可能性を秘め、「小児疾患」に悩まされることはなく、原則として同じスイスの時計のように機能します。 また、以前のバージョンからのすべての成果は、元のクラスがより孤立しているほど簡単に転送されます。



参照:
  1. ビョルン・ストラウストルプ。 C ++プログラミング言語。
  2. アランI.ゴラブ「足で自分を撃つのに十分な長さのロープ」


次の部分では 、新しい/削除の問題に別れを告げ、スマートポインターとガベージコレクターの必要性を取り除き、リソースを操作するより単純で自然な方法に置き換えます。



All Articles