ホームページ > 記事 > コンピューターのチュートリアル > Unix の哲学 プログラミング原則
Unix の哲学は、豊富な経験に基づいた実用性を重視しており、従来の方法論や標準に制限されません。この知識はより潜在的で、半ば本能的なものです。 Unix プログラマが開発経験を通じて蓄積した知識は、他のプログラマにも役立ちます。
(1) 元のプログラムに新しい機能が追加されて複雑さが増すことを避けるために、各プログラムは 1 つのタスクを完了することに集中し、新しいタスクが見つかったら最初からやり直す必要があります。 (2) 次のプログラムが不明であっても、プログラムの出力が別のプログラムの入力となることを想定し、出力に無関係な情報が含まれないようにする。 (3) 設計・作成したソフトウェアはできるだけ早く試用し、低品質なコードは思い切って捨てて書き直してください。 (4) 非効率な補助手段より先にツールを使用して、プログラミング作業の負担を軽減する 卓越性を追求するには、ツールを上手に活用する必要があります。
Unix 哲学の本質は、賢者たちが口頭で伝えたことだけではなく、彼らの実践や Unix システム自体の設計に反映されています。この哲学は、いくつかの重要なポイントに要約できます:
ソフトウェア エンジニアリングを初めて使用する場合は、これらの原則を深く理解する必要があります。ほとんどの記事はこれらの原則を推奨していますが、多くのシステムには実用的なツールや伝統が欠如しており、プログラマがこれらの原則を実装するのを妨げています。多くの場合、貧弱なツール、貧弱な設計、過重労働、冗長なコードによって妨げられます。
プログラミングの核心は複雑さを管理することです。バグの解決には開発時間の大部分がかかります。使いやすいシステムの成功は、才能や設計スキルだけではなく、試行錯誤の結果です。
アセンブリ言語、コンパイル言語、フローチャート、手続き型プログラミング、構造化プログラミング、オブジェクト指向、およびソフトウェア開発方法論が過剰に宣伝されています。しかし、それらは人間の脳の処理能力を超えてプログラムの複雑さを増大させます。
複雑なソフトウェアの開発を成功させるには、全体の複雑さを軽減し、シンプルなモジュールの明確なインターフェイスを通じてソフトウェアを組み合わせることが重要です。これにより、問題が特定の部分に限定され、全体に影響を与えることなくその領域を改善しやすくなります。
将来のメンテナンスの複雑さとコストを念頭に置いてコードを作成します。コードは読みやすく、理解しやすく、必要に応じて他の人や自分自身が簡単に変更および保守できるようにする必要があります。
Unix の伝統では、この原則はコード コメントだけに適用されるわけではありません。 Unix のベスト プラクティスでは、アルゴリズムと実装を選択するときに将来のスケーラビリティを考慮することも重視しています。プログラムのパフォーマンスを少し向上させるために、技術的な複雑さや混乱を加えたくなるかもしれませんが、このアプローチには利益をもたらす価値はありません。これは、複雑なコードにはバグが発生しやすいだけでなく、将来の読み取りや保守がより困難になるためでもあります。逆に、エレガントで明確なコードは安定性が高いだけでなく、他の人にとっても理解しやすく、変更しやすくなります。特に、数年後にこのコードに戻って変更する必要があるのはあなたである可能性があるため、これは非常に重要です。
難解なコードを 3 回解読するのに苦労する必要はありません。最初はうまくいくかもしれませんが、もう一度再解釈する必要があることがわかった場合、つまり最初から時間が経ちすぎて具体的な詳細を思い出せない場合は、コードをコメント アウトします。 3回目は比較的痛みが軽くなります。
プログラムが相互に効果的に通信できない場合、ソフトウェアは必然的に複雑さの泥沼にはまってしまいます。
入出力に関しては、Unix の伝統は、シンプルでテキスト形式、ストリーム指向、デバイスに依存しない形式の使用を強く推奨しています。従来の Unix では、ほとんどのプログラムは可能な限り単純なフィルターの形式を採用しています。つまり、入力テキスト ストリームを処理して単純なテキスト ストリーム出力を生成します。従来の通念に反して、Unix プログラマがこのアプローチを好むのは、グラフィカル ユーザー インターフェイスが嫌いだからではなく、単純なテキスト入出力ストリームを使用しない場合、プログラムのインターフェイスが非常に困難になるためです。
Unix のテキスト ストリームは、ツールにとって、オブジェクト指向環境のオブジェクトにとってのメッセージと同じです。テキスト フロー インターフェイスのシンプルさにより、ツールのカプセル化が強化されます。リモート プロシージャ コールなどの多くの高度なプロセス間通信方法では、関与するプロセスが多すぎる傾向があります。
プログラムをコンポーザブルにするには、プログラムを互いに独立させる必要があります。テキスト ストリームの一方の端のプログラムは、できる限りテキスト ストリームの他方の端のプログラムを考慮しないようにする必要があります。もう一方の側にまったく影響を与えることなく、一方の側のプログラムをまったく別のプログラムに置き換えるのは簡単でなければなりません。 GUI は良いものです。GUI を作成する前に、複雑なインタラクティブなプログラムと、大まかな作業を行うアルゴリズム プログラムを分離できるかどうかを検討する必要があります。それぞれの部分を別個の部分に作成し、簡単なコマンドを使用できます。フローまたはアプリケーション プロトコルを組み合わせて、すべてを組み合わせます。
高度なデータ伝送フォーマットを考える前に、単純なテキストデータフォーマットが利用可能かどうかを現場で確認する必要があるが、フォーマットを少し解析するコストはかかるが、汎用ツールを利用して構築できるメリットがあるまたはデータ ストリームを解釈する価値があります。
プログラムがシリアル化されたプロトコルベースのインターフェイスを自然に使用できない場合、正しい Unix 設計は、少なくとも可能な限り多くのプログラミング要素を明確に定義された API のセットに編成することです。このようにして、アプリケーションは少なくともリンクを通じて呼び出すことができ、さまざまなタスクのニーズに応じてさまざまなインターフェイスを結合することができます。
戦略とメカニズムはさまざまな時間スケールに応じて変化し、戦略はメカニズムよりもはるかに速く変化します。戦略とメカニズムを組み合わせると、2 つのマイナスの影響が生じます。1 つは、戦略が硬直的になり、ユーザー ニーズの変化に適応するのが困難になることです。2 つ目は、戦略の変更がメカニズムを揺るがす可能性が高いことを意味します。逆に、新しい戦略を模索する場合、この 2 つを剥ぎ取ってもメカニズムを破壊するのに十分ではない可能性があります。さらに、メカニズムのより優れたテストを作成するのも簡単になります。
ストリッピングを実現する方法は、アプリケーションをフロントエンド プロセスとバックエンド プロセスに分割し、ソケットの上位層の専用アプリケーション プロトコルを介して連携および通信できるようにすることです。フロントエンド実装戦略、バックエンド実装メカニズム。単一プロセスのみを使用して全体を実装する場合と比較して、この両端の設計により全体の複雑さが大幅に軽減され、バグが減少し、それによってプログラムのライフサイクルコストが削減されることが期待されます。
少なくともビジネス ソフトウェアの世界では、過剰な複雑さはプロジェクト要件から生じることが多く、これらの要件は顧客のニーズやソフトウェアが実際に提供できるものではなく、プロモーションのホットスポットに基づいていることがよくあります。多くの優れた設計は、ほとんど使用されない機能として販売される長い機能リストによって台無しになります。他の人よりも派手になるには、自分自身がさらに派手になるという悪循環が始まります。間もなく、肥大化が業界標準となり、バグが多すぎて肥大化したソフトウェアを誰もが使用するようになり、ソフトウェア開発者ですらそれを真剣に受け止めようとはしませんでした。
これらの落とし穴を回避する唯一の方法は、シンプルさが美しいという別のソフトウェア文化を奨励することです。これは、シンプルなソリューションを重視し、常にプログラム システムを連携して動作できる小さな部分に分割しようとし、あまりにも多くのギミックでプログラムを表面化しようとする試みに本能的に抵抗するエンジニアリングの伝統です。
「ビッグ」には、サイズが大きいことと複雑さの高さという 2 つの意味があります。プログラムが大きくなるほど、保守は難しくなります。多大な労力をかけて作成したものを手放すのは難しいため、失敗する運命にある、または最適なソリューションではない巨大なプログラムへの投資が無駄になってしまいます。不要なコードとロジックを避け、コードを無駄のない状態に保ちます。
デバッグには開発時間の 4 分の 3 以上がかかることが多いため、最初に少しだけ多くの作業を行って、後のデバッグ作業の量を減らすことは有益です。デバッグ作業の負荷を軽減するには、設計時に透明性と可視性を十分に考慮することが効果的です。
ソフトウェア システムの透明性とは、ソフトウェアが何をしているのか、どのように実行しているのかが一目でわかることを意味します。可視性とは、プログラムが内部状態を監視および表示する機能を備えていることを意味し、プログラムが適切に実行されるだけでなく、どのように実行されるかも確認できます。
これらの要件が設計時に十分に考慮されていれば、プロジェクト プロセス全体にメリットがもたらされます。デバッグ オプションの設定は、事後的に行うべきではなく、設計の初めに考慮する必要があります。プログラムは、その正しさを実証できるだけでなく、後発開発者に元の開発者の問題解決方法を知らせることができる必要があります。思考モデル。
プログラムがその正しさを実証したい場合は、有効な入力と正しい出力の関係が正しいかどうかを簡単にチェックできるように、十分に単純な入出力形式を使用する必要があります。透明性と可視性を高めるために、他のプログラム、特にテスト監視ツールやデバッグ スクリプトの操作を容易にするために、シンプルなインターフェイスも推進する必要があります。 WeChat パブリック アカウントをフォローしてください [組み込みシステム]
ソフトウェアの堅牢性とは、ソフトウェアが通常の状況下で適切に動作するだけでなく、想像を超える予期せぬ状況下でも適切に動作できることを意味します。
ほとんどのソフトウェアは衝突に耐えることができず、すべての側面を考慮することがあまりにも複雑で難しいため、多くの問題を抱えています。プログラムのロジックを正しく理解できなければ、それが正しいかどうか確信が持てず、何か問題が発生したときに修正することもできません。プログラムを堅牢にする方法は、プログラムの内部ロジックを理解しやすくすることであり、これを行うには主に 2 つの方法があります: 透明性と単純さです。
堅牢性の観点からは、極端な入力に耐えられるように設計することも重要です。異常な入力の場合、ソフトウェアの堅牢性を確保するための非常に重要な戦略は、コード内の特殊なケースを回避することです。バグは通常、特殊なケースを処理するコードや、さまざまな特殊な状況での対話型操作を処理するコードに隠されています。
ソフトウェアの透明性とは、何が起こっているかを一目で確認できることを意味します。 「何が起こっているのか」が複雑でない場合、つまり、考えられるすべてのシナリオを頭を悩ませることなく推測できる場合、プログラムは単純です。プログラムがシンプルで透明であればあるほど、より堅牢になります。
モジュール化 (単純なコード、単純なインターフェイス) は、より簡潔な目的を達成するためにプログラムを編成する方法です。
データはプログラミング ロジックよりも制御しやすいため、設計ではコードの複雑さを積極的にデータに反映する必要があります。
この考慮事項は Unix 独自のものではありませんが、多くの Unix コードはこの考慮事項の影響を受けているようです。特に、ポインタの使用を制御する C 言語の機能により、カーネルより上のさまざまなコーディング レベルでの参照構造の動的な変更が促進されます。構造体での非常に単純なポインター操作で実行できるタスクは、多くの場合、他の言語ではより複雑な手順を必要とします。
データ駆動型プログラミングを行う場合は、コードと、そのコードが動作するデータ構造を明確に分離する必要があります。こうすることで、プログラムのロジックを変更するときは、プログラムのロジックを変更するのではなく、データ構造のみを編集する必要があります。コード。データ駆動型プログラミングは、データ編成を中心とした別のスタイルであるオブジェクト指向プログラミングと混同されることがあります。それらの間には少なくとも 2 つの違いがあります。第一に、データ駆動型プログラミングでは、データは単なるオブジェクトの状態ではなく、実際にプログラムの制御フローを定義します。第二に、オブジェクト指向ではまずカプセル化が考慮されますが、データ駆動型プログラミングでは同様に書き込みが重視されます。できる限り固定コードを減らします。
これは「最小驚きの原則」としても知られています。最も使いやすいプログラムとは、ユーザーが新しいことを学ぶ必要が最も少なく、ユーザーの既存の知識に最も適合するプログラムです。したがって、インターフェイスのデザインでは、不当な新規性や巧妙さを避ける必要があります。
電卓をプログラムする場合、「 」は常に加算を意味する必要があります。インターフェイスを設計するときは、ユーザーが最もよく知っている同じ機能のインターフェイスや類似のアプリケーションに従ってインターフェイスをモデル化するようにしてください。
対象ユーザーに焦点を当てます。対象ユーザーはエンド ユーザー、他のプログラマ、システム管理者である可能性があります。最も驚くべきことではないということは、これらのさまざまなグループの人々にとっては異なる意味を持ちます。従来の慣例に焦点を当てます。これには、学習曲線を緩和するという正当な理由があります。
最小限のイノベーションの原則のもう一方の側面は、似ているように見えても実際にはわずかに異なることを避けることです。見かけの類似性によって人々が誤った推測をしてしまうことがよくあるため、これは非常に危険な場合があります。なので、見た目はほぼ同じよりも明らかに違うもののほうが良いのです。
正常に動作するプログラムは、静かに動作し、チャタリングが発生しないようにする必要があります。沈黙は金です。この原則は、Unix が誕生したとき、ビデオ モニターがなかったという事実に由来しています。冗長な出力のすべての行は、ユーザーの貴重な時間を大幅に消費することになります。この状況はもう存在しませんが、すべてをシンプルに保つという優れた伝統は今日まで続いています。
シンプルさは Unix プログラムの中核的なスタイルです。プログラムの出力が別のプログラムの入力になると、必要なデータを簡単に選択できます。人間の観点からすると、重要な情報は、プログラムの内部動作に関する長い情報と混同されるべきではありません。表示された情報がすべて重要であれば、それを探す必要はありません。適切に設計されたプログラムは、ユーザーの注意を限られた貴重なリソースとして扱い、不必要な情報でユーザーの邪魔をしないように、必要な場合にのみ使用する必要があります。
ソフトウェアは、エラーが発生した場合でも、通常の動作時と同じ透過的なロジックを備えている必要があります。もちろん、最良のシナリオは、ソフトウェアが異常な動作に適応して対処できることですが、最悪のシナリオは、修復措置が明らかに失敗しているにもかかわらず、クラッシュのリスクが黙って埋もれている場合であり、それはかなりの期間が経過するまで明らかにされません。後で。
したがって、ソフトウェアは、さまざまな誤入力や自身の実行エラーにできるだけ冷静に対処する必要があり、それができない場合は、エラーを診断しやすい方法でプログラムをできるだけ終了させます。
「寛容に受信し、慎重に送信します。」たとえ入力データが標準化されていないとしても、よく設計されたプログラムは、その意味を理解して他のプログラムと可能な限り連携しようとし、その後、大きく崩れるか、プログラムにとって厳密でクリーンで正しいデータを出力します。作業チェーンの次のリンク。
標準の欠点を補うために過度に贅沢な実装を使用するのではなく、設計時に寛容性を考慮する必要があります。そうしないと、注意しないと醜く死ぬことになります。
Unix の初期のミニコンピュータ時代では、この考え方は非常に過激でした。技術の発展に伴い、開発会社やほとんどのユーザーは安価なマシンを入手できるようになったので、この基準の合理性は言うまでもありません。
品質を確保するという前提の下で、コンピューター リソースを使用してタスクを完了し、プログラマーの負担を軽減するように努めます。プログラマーの時間を大幅に節約するもう 1 つの方法は、より低レベルのプログラミング作業を行う方法をマシンに教えることです。 WeChat パブリック アカウントをフォローしてください [組み込みシステム]
人間は細かい作業をするのが苦手であることはよく知られています。プログラム内での手動作業はエラーや遅延の温床となり、プログラムで生成されたコードはほとんどの場合、手書きのコードよりも安価で信頼性が高くなります。
コード ジェネレーターの場合、手書きを必要とする反復的で鈍い高級言語コードを、機械語コードと同様に大量生産できます。コード ジェネレーターを使用すると、抽象化のレベルが高まるとき、つまり、ジェネレーターの宣言ステートメントが生成されたコードよりも単純になり、生成されたコードによって面倒な手動処理が不要になるときに効果が得られます。コード ジェネレーターは、エラーが発生しやすい詳細な作業を自動化するために Unix で広く使用されています。
プロトタイプ設計の最も基本的な原則は、「機能の 90% が今実現可能であるが、機能の 100% が実現されないよりは優れている」ということです。プロトタイピングを適切に行うことで、わずかな利益のために多大な時間を投資することを避けることができます。
「些細な利益の効率化を考えるべきではありません。時期尚早な最適化が諸悪の根源です。」 ボトルネックがどこにあるのかわからないまま最適化を急ぐことは、ランダムな機能を追加することよりも設計にダメージを与える唯一の間違いかもしれません。変形したコードから整理されていないデータ レイアウトに至るまで、透明性と簡素性を犠牲にして速度を一方的に追求することにより、無数のバグが発生し、何百万人もの時間が費やされます。このわずかなメリットは、その後のトラブルシューティングのコストを相殺するものではありません。
時期尚早のローカル最適化は、実際にはグローバル最適化を妨げ、全体的なパフォーマンスを低下させる可能性があります。設計全体に大きなメリットをもたらす変更は、時期尚早な局所最適化によって妨げられることが多く、その結果、製品のパフォーマンスが低下し、コードが過度に複雑になってしまいます。
Unix の世界には、最初にプロトタイプを作成し、次に改良するという非常に明確で長い伝統があります。最適化する前に、使用できることを確認してください。まず、歩けるようになり、次に走ることを学びます。これを異なる文化から効果的に拡張したものです。最初に走り、次に正しく行動し、最後に速く進みます。
これらすべての言葉の本質は実際には同じことを意味します: まず、最適化されておらず、遅く、メモリを消費するが、正しい実装を設計し、次に体系的な調整を行って、最小限のローカルの単純性を犠牲にすることで得られるものを見つけます。パフォーマンスの向上。
最高のソフトウェアであっても、設計者の想像力によって制限されることがよくあります。すべてを最適化できるほど賢い人はいませんし、ソフトウェアのあらゆる用途を予測することもできません。
ソフトウェアの設計と実装に関して、Unix の伝統の良い点の 1 つは、いわゆる「画一的なアプローチ」を決して信じないことです。 Unix は、多言語の普及、オープンでスケーラブルなシステム、ユーザーによるカスタマイズ機構を追求し、さまざまな優れた設計アイデアを吸収して活用し、独自の設計手法とスタイルを継続的に改善しています。
データ形式とコードを拡張する余地を残しておいてください。そうしないと、オリジナルとの互換性を維持しながら変更することができないため、オリジナルの賢明でない選択に縛られることがよくあります。
プロトコルまたはファイル形式を設計するときは、拡張可能であるために十分に自己記述的である必要があります。バージョン番号を含めるか、独立した自己記述ステートメントを使用して、フォーマットを読み取るコードを中断することなく、いつでも新しいものを挿入したり古いものを交換したりできるようにフォーマットを編成します。 Unix の経験から、データ デプロイメントを自己記述型にするオーバーヘッドをわずかに増やすことで、全体を破壊することなく拡張でき、小さな努力が何千倍も報われることがわかります。
コードを設計するときは、将来の開発者がアーキテクチャ全体を破壊したり再構築したりせずに新しい機能を追加できるように、コードをよく整理する必要があります。この原則は、使用しない関数を自由に追加できるという意味ではなく、将来の関数を追加しやすくするために、コードを記述するときに将来のニーズを考慮する必要があるという意味です。プログラム インターフェイスは柔軟である必要があります。コードにコメント「拡張...が必要な場合...」を追加します。将来、作成したコードを使用および保守する人のために、何か良いことをする義務があります。おそらく保守するでしょう。将来的には自分でコードを作成し、将来を念頭に置いて設計することで、節約できるのは自分自身のエネルギーになる可能性があります。
これらの哲学原則は決して曖昧で一般的なものではありません。 Unix の世界では、これらの原則は実践から直接得られ、特定のルールを形成します。
Unix 哲学を使用して、私たちは常に卓越性を追求する必要があります。ソフトウェア設計は、知恵、創造性、そして情熱に値する工芸品です。そうしないと、単純で時代遅れの設計や実装を超えられず、考えるべきときに急いでプログラムを作成し、複雑な部分を容赦なく切り取って単純化する必要があるときに問題を複雑にし、その理由について不平を言うことになります。コードが非常に肥大化しており、デバッグが困難です。
Unix の哲学を有効に活用するには、決して無謀な行動をしないでください。より多くのスキルを使用し、必要なときに使用できるようにエネルギーを節約してください。刃には良質の鋼を使用してください。ツールを活用し、可能な限りすべてを自動化します。
ソフトウェアの設計と実装は、喜びに満ちた芸術であり、高度なゲームです。他のことではなく、なぜソフトウェア設計に取り組む必要があるのでしょうか? もしかしたら、今は単にお金を稼ぐか、時間を潰すためだけかもしれませんし、あるいはソフトウェア設計は世界を変えるものであり、情熱を注ぐ価値があるとかつては考えていたかもしれません。
以上がUnix の哲学 プログラミング原則の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。