前言#
著者はソフトウェアの専門家ではないため、これまでプログラミングの設計を積極的または受動的に学んだことはなく、観察と実践に基づく経験主義です。
また、組み込みシステムはこれらにあまり関心を持たず、主に RAM/ROM の使用量、実行速度、ビジネスロジックが要件を満たしているかどうかを評価することに重点を置いています。これにより、特定の製品に特化した成果物が多く生まれるという深刻な問題が生じます。
ここで 2 つの議論があります。
- 本当にリソースが制限された MCU 上で再利用可能なコードを使用することはできないのでしょうか?私は否定的だと思います。その理由については後で議論します。
- このようにカスタマイズされたソフトウェアコードのアーカイブは、ほとんどコメントがなく説明もほとんどないため、本当に
ソフトウェア資産
と呼べるのでしょうか?私個人の意見では否定的です。私の認識では、初学者が 8 時間以内に無指導で使用できるソフトウェアモジュールは不合格です。
最近、真のソフトウェア資産
を生み出す方法を考えたいと思い、基本的なプログラミング設計を理解する必要があります。そのため、10 分間で完全に理解しました
以下はこれらの設計についての机上の空論です。笑って流してください。私はこれらのことを実際にあまり実践していません。
オブジェクト指向プログラミング#
オブジェクト指向は使い古された言葉ですが、私はその専門用語を完全には理解していません。
私の見解では、オブジェクト指向の本質は、ある事物の定義に向けられています。つまり、ある事象がどのような機能、変数、定量を含むかを定義することです。例えば、私たちはキーボードを定義します。104 個のキーと「A を押す」「B を押す」という機能があります。
しかし、違いますね。市場には奇形のさまざまなキーボードが存在します。これはいわゆる「継承」に関係しており、奇形のキーボードは私たちの標準キーボードクラスのいくつかの要素を再定義しただけです。例えば、テンキーの「1 を押す」機能を無効にしたり、88 個のキーがあると再定義したりします。
オブジェクト指向の世界では、すべてがオブジェクトとして定義され、その後オブジェクトを定義し、そのオブジェクトのイメージを固定し、継承と拡張を行うことでモジュールを実現します。そして、複数のオブジェクトを組み合わせてプロジェクトを実現します。
私は、移植の難易度と機能のバランスを考慮した場合、オブジェクト指向プログラミングはモジュール化の最良の実現方法であると考えています(今のところはそう思っています)。
しかし、プロジェクトの観点から見ると、オブジェクト指向は非常に不親切です。プロジェクトの進行中に、あるオブジェクトの事象の定義が変わった場合、システム全体が大きく変わり、問題の原因を特定するのが難しくなります。各オブジェクトの使用に対して中間層を追加して隔離する場合、それは完全に無駄で新しい定義を生むことになります。要するに、定義の変化は影響が大きすぎて、実際にはメンテナンスを行う人にとってはあまり親切ではありません。
私たちは実際には快適でありたいのです。前を見たり後ろを見たり、レベルが異なり、混沌とした状態では快適ではありません。
関数型プログラミング#
主に1.7. 范畴論入門 (*) - バナナスペースを参考にしています。この参考資料は数学の知識のみを紹介し、プログラミングには関与していません。
これは実際には難しくありません。すべては関数です。しかし、すべてが関数でありながらビジネス機能を実現できるのは非常に不思議です。
関数型プログラミングには、最も重要な 2 つのルールがあります(私の見解です)。
- すべての関数には入力と出力が必要です。
- すべての関数は、どんな状況でも同じ入力に対して同じ出力を持ちます。
私の見解では、関数型の本質は副作用のない確定的な機能を持つ関数を得ることです。
以下の図では、各矢印が 1 つの関数であり、各点が入力でもあり出力でもあります。例えば、左から最初の矢印は、最初の点がこの関数に入力され、出力は 2 番目の点になります。そして、2 番目の点は 2 つの関数を介して別の 2 つの点に変わることができます。ここでの点は何でもあり得ます。もちろん、この考え方の下では、何でも関数であり、実数値は固定出力の関数であり、変数を取ることは単位射です1。
例えば、CRC16 アルゴリズムの実装やさまざまな古典的暗号アルゴリズムの実装は、必ず関数型プログラミングです。検証値 / 平文のセットは、関数を通じて必ず検証値 / 暗号文のセットを出力します。その検証プロセスや解析も同様に関数型であるため、これらの 2 つのシナリオでは入力と出力が同型です2。
私たちは、すべての純粋な数学的問題において、関数型プログラミングを使用することが簡単であることを発見できます。数学が世界を記述できるという議論はしないでください。
しかし、実際のエンジニアリングでは、すべての状態を単純に定義することは不可能であり、大きな入力と出力が関与し、関数の作成も困難です。また、関数の数もそれほど少なくはないと思います。問題を分解すると、関数の数は膨大になります。
実際、関数型プログラミングは産業思考に合致しています。確定的な動作が確定的なフィードバックをもたらし、特定の有限の状況に対するビジネスロジックには関数型プログラミングを使用することができますが、相対的に管理が難しい状態機械を使用する必要はありません。
ここで前言の「議論 1:本当にリソースが制限された MCU 上で再利用可能なコードを使用することはできないのでしょうか?」に戻ります。明らかに、関数型プログラミングはどんな状況でも消費するリソースが似ています。私たちは範疇 3を縮小し、不要な関数を削除して再利用を実現できます。
私の見解は、関数型で数学に関連する関数を書くことは良いカプセル化ですが、この思考をエンジニアリングやビジネスに持ち込む必要はなく、作業量は純粋に指数関数的に増加します。
おそらく命令生成も良い関数型の方向性であり、改造の機会があります。
手続き型プログラミング#
上記の 2 つのプログラミング手法は、関数 / メソッドの副作用を減らし、異なるシステムでほぼ同じ機能を得ることを目的としています。手続き型は異なります。手続き型の本質は、副作用を使用して望む機能を得ることであり、さまざまな関数 / メソッドの中で入力値 / 出力値を使って移動することではありません。
手続き型は、人が解決策を考える際に最も適したプログラミング方式です。詳細は省略しますが、皆さんは理解しています。
まとめ#
要するに、ソフトウェア資産
の層構造において、最下層は関数型プログラミングによって形成されたコンポーネントモジュールであり、機能モジュールはオブジェクト指向プログラミングを採用し、関数型コンポーネントを呼び出すというのが私の考えです。
最も古典的なケースを考えてみましょう。「象を冷蔵庫に入れる」。
オブジェクト指向プログラミングでは、象オブジェクトの定義、冷蔵庫の定義(ストレージスペース、投入方法、取り出し方法を含む)を実現し、2 つのオブジェクトをインスタンス化し、その後冷蔵庫の投入方法を使用します。
関数型プログラミングでは、3 つの物件 —— 空の物件、冷蔵庫、象、象を入れた冷蔵庫を事前に定義し、関数 1 は「空の物件」を入力として「冷蔵庫と象」を出力し、関数 2 は「冷蔵庫と象」を入力として「象を入れた冷蔵庫」を出力します。
手続き型プログラミングでは、象を捕まえる関数(副作用は象を生成する)、冷蔵庫を買う関数(副作用は冷蔵庫を生成する)、象を冷蔵庫に詰める関数(副作用は冷蔵庫を象を入れた冷蔵庫に変更する)です。
この記事は Mix Space によって xLog に同期更新されました。元のリンクは https://www.yono233.cn/posts/novel/25_4_25_coder です。