コードを最小化し、データを最大化するという概念を聞いたことがありますが、独自のシステムを構築するときにこれをどのように/なぜ行うべきかについて、他の人がどのようなアドバイスをくれるのでしょうか?
6 に答える
通常、データ駆動型コードは読みやすく、保守も簡単です。データ駆動型が極端になり、非常に使用できなくなるケースを見たことがあることは知っていますが(私が使用したいくつかのSAPデプロイメントを考えています)、独自の「ドメイン固有言語」をコーディングして構築を支援します通常、ソフトウェアは大幅な時間の節約になります。
実用的なプログラマーは、私が読んだ小さな言語を書くことの最も鮮やかな支持者であり続けています。小さな入力言語を実行する小さなステートマシンは、非常に少ないスペースで多くのことを達成でき、変更を簡単に行うことができます。
具体的な例:1,000ドル、10,000ドル、100,000ドルの税率の累進所得税システムについて考えてみます。1,000ドル未満の所得は非課税です。1,000ドルから9,999ドルの間の所得は、10%で課税されます。10,000ドルから99,999ドルの間の所得は、20%で課税されます。そして、$ 100,000を超える所得は30%で課税されます。あなたがこれをすべてコードで書き出すならば、あなたが疑うようにそれは見回すでしょう:
total_tax_burden(income) {
if (income < 1000)
return 0
if (income < 10000)
return .1 * (income - 1000)
if (income < 100000)
return 999.9 + .2 * (income - 10000)
return 18999.7 + .3 * (income - 100000)
}
新しい税括弧の追加、既存の括弧の変更、または括弧内の税負担の変更はすべて、コードを変更して再コンパイルする必要があります。
ただし、データ駆動型の場合は、このテーブルを構成ファイルに保存できます。
1000:0
10000:10
100000:20
inf:30
このテーブルを解析してルックアップを実行するための小さなツールを作成します(それほど難しくはありませんよね?)。これで、誰でも簡単に税率テーブルを管理できます。議会が1000括弧の方が良いと判断した場合、誰でもテーブルをIRSテーブルと整列させることができ、コードを再コンパイルする必要はありません。同じ一般的なコードを1つのブラケットまたは数百のブラケットに使用できます。
そして今、もう少し明白ではない何かのために:テスト。AppArmorプロジェクトには、さまざまなプロファイルがロードされたときにシステムコールが実行する必要があることについての何百ものテストがあります。1つのサンプルテストは次のようになります。
#! /bin/bash
# $Id$
# Copyright (C) 2002-2007 Novell/SUSE
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, version 2 of the
# License.
#=NAME open
#=DESCRIPTION
# Verify that the open syscall is correctly managed for confined profiles.
#=END
pwd=`dirname $0`
pwd=`cd $pwd ; /bin/pwd`
bin=$pwd
. $bin/prologue.inc
file=$tmpdir/file
okperm=rw
badperm1=r
badperm2=w
# PASS UNCONFINED
runchecktest "OPEN unconfined RW (create) " pass $file
# PASS TEST (the file shouldn't exist, so open should create it
rm -f ${file}
genprofile $file:$okperm
runchecktest "OPEN RW (create) " pass $file
# PASS TEST
genprofile $file:$okperm
runchecktest "OPEN RW" pass $file
# FAILURE TEST (1)
genprofile $file:$badperm1
runchecktest "OPEN R" fail $file
# FAILURE TEST (2)
genprofile $file:$badperm2
runchecktest "OPEN W" fail $file
# FAILURE TEST (3)
genprofile $file:$badperm1 cap:dac_override
runchecktest "OPEN R+dac_override" fail $file
# FAILURE TEST (4)
# This is testing for bug: https://bugs.wirex.com/show_bug.cgi?id=2885
# When we open O_CREAT|O_RDWR, we are (were?) allowing only write access
# to be required.
rm -f ${file}
genprofile $file:$badperm2
runchecktest "OPEN W (create)" fail $file
いくつかのヘルパー関数を使用して、プロファイルを生成およびロードし、関数の結果をテストして、ユーザーに報告します。この種の機能を少しの言語なしで書くよりも、これらの小さなテストスクリプトを拡張する方がはるかに簡単です。はい、これらはシェルスクリプトですが、実際のシェルスクリプトからはかなり削除されているため、実際にはデータです。
これがデータ駆動型プログラミングの動機付けに役立つことを願っています。私はそれについて書いた他の人ほど雄弁ではないのではないかと思います、そして私は確かにそれが得意ではありませんが、私は試みます。
最新のソフトウェアでは、コードとデータの境界が非常に薄くなり、あいまいになることがあり、両者を区別するのは必ずしも容易ではありません。結局のところ、コンピューターに関する限り、既存のコード (通常は OS) によってそうでないと判断されない限り、すべてがデータです。プログラムでさえ、CPU がプログラムを実行する前に、データとしてメモリにロードする必要があります。
たとえば、注文のコストを計算するアルゴリズムを想像してみてください。注文が多いほど、アイテムごとの価格が低くなります。これは、C で書かれた店舗内の大規模なソフトウェア システムの一部です。
このアルゴリズムは C で記述されており、さまざまなアイテムごとの価格と対応する注文サイズのしきい値を含む、経営陣によって提供された入力テーブルを含むファイルを読み取ります。ほとんどの人は、単純な入力テーブルを持つファイルはもちろんデータであると主張するでしょう。
ここで、ストアが非常に大量の注文に対応できるように、事前に選択されたしきい値ではなく、ある種の漸近関数にポリシーを変更したとします。彼らはまた、為替レートとインフレ、または経営陣が思いついたその他のものを考慮に入れたいと思うかもしれません.
ストアは有能なプログラマーを雇い、彼女は優れた数式パーサーを元の C コードに組み込みます。入力ファイルには、プランク定数や炭素 14の分解率などの単純なものだけでなく、グローバル変数、log()
やなどの関数を含む式が含まれています。tan()
cost = (base * ordered * exchange * ... + ... / ...)^13
ほとんどの人は、表ほど単純でなくても、式は実際にはデータであると主張します。結局のところ、それはおそらく管理によってそのまま提供されます。
その店には、経費を見積もろうとして脳死状態になった顧客や、会計担当者から、大量の小銭についての苦情が大量に寄せられます。店舗は、少量の注文にはテーブルに戻り、大量の注文にはフィボナッチ数列を使用することにしました。
プログラマーは C コードの変更と再コンパイルにうんざりしているため、代わりに Python インタープリターを組み込みます。Fib(n)
入力ファイルには、大きな注文のコストを求めて部屋一杯のサルをポーリングする Python 関数が含まれています。
質問:これは入力ファイルのデータですか?
厳密な技術的な点からは、何も違いはありません。テーブルと式の両方を使用前に解析する必要がありました。数式パーサーは、おそらく分岐と関数をサポートしていました。チューリング完全ではなかったかもしれませんが、それでも独自の言語 (MathML など) を使用していました。
しかし今では、多くの人が入力ファイルがコードになっただけだと主張するでしょう。
では、入力形式をデータからコードに変換する特徴的な機能は何ですか?
変更可能性: 変更を有効にするためにシステム全体を再コンパイルする必要があることは、コード中心のシステムの非常に良い兆候です。それでも、コンパイル時に入力テーブルを組み込むなど、無能に設計されたソフトウェアを簡単に想像できます (まあ、実際に見たようなものです)。そして、多くのアプリケーションには、実行可能ファイルに組み込まれたアイコン (ほとんどの人がデータと見なすアイコン) がまだあることを忘れないでください。
入力形式:これは、私の意見では、単純に、人々が考える最も一般的な要因です: 「プログラミング言語であれば、それはコードです」 . C はコードです。結局のところ、コンパイルする必要があります。また、Python もコードであることに同意します。これは本格的な言語です。では、なぜXML/XSL コードではないのでしょうか? XSLは、それ自体が非常に複雑な言語
L
です。
私の意見では、これら 2 つの基準のいずれも、実際の際立った特徴ではありません。私は人々が何か他のことを考えるべきだと思います:
- 保守性:つまり、システムの動作を変更するために必要な専門知識を利用できるようにするために、システムのユーザーがサードパーティを雇わなければならない場合、システムはある程度コード中心であると見なされるべきです。
もちろん、これは、システムがデータ駆動型であるかどうかを、少なくともターゲット ユーザーとの関係で検討する必要があることを意味します。
また、使用可能なツールセットによって区別が影響を受ける可能性があることも意味します。UML仕様は悪夢のようなものですが、最近ではグラフィカルな UML エディターがすべて役立ちます。自然言語を解析して XML や Python などを生成するサードパーティ製の高レベル AI ツールがあれば、システムははるかに複雑な入力に対してもデータ駆動型になります。
小規模な店舗には、サードパーティを雇うための専門知識やリソースがない可能性があります。したがって、労働者が平均的な管理コースで得られる知識 (数学、チャートなど) を使用して自分の行動を変更できるようにするものは、この聴衆にとって十分にデータ駆動型であると見なすことができます。
一方、数十億規模の国際企業は通常、多くの IT スペシャリストと Web デザイナーを雇用しています。したがって、XML/XSL、Javascript、または Python と PHP でさえ、おそらく十分に扱いやすいでしょう。また、複雑な要件があるため、単純なものではうまくいかない可能性があります。
ソフトウェアシステムを設計するときは、サードパーティを頻繁に呼び出すことなく、ターゲットオーディエンスが必要なことを実行できるように、使用される入力形式の微妙なバランスを達成するよう努めるべきだと私は信じています.
アウトソーシングは、境界線をさらにあいまいにすることに注意する必要があります。かなりの数の問題があり、その問題については、現在のテクノロジでは、素人が簡単に解決することはできません。その場合、ソリューションの対象者はおそらく、運用が外部委託されるサード パーティであると見なされるべきです。その第三者は、かなりの数の専門家を雇用することが期待できます。
他の回答は、特定の入力のパターンに反応するだけの単純なコードで複雑な動作を頻繁にコーディングする方法をすでに掘り下げています。データをドメイン固有の言語と見なし、コードをインタープリター (おそらく単純なもの) と考えることができます。
多くのデータがあれば、さらに先に進むことができます。統計は意思決定に影響を与える可能性があります。Peter Norvig はBeautiful Dataでこのテーマを説明する素晴らしい章を書きました。テキスト、コード、データはすべてオンラインで入手できます。(開示: 謝辞で感謝します。) pp. 238-239:
データ駆動型のアプローチは、プログラマーが明示的なルールをコーディングする従来のソフトウェア開発プロセスと比べてどうですか? ... 明らかに、手書きのルールは開発と維持が困難です。データドリブン手法の大きな利点は、データに非常に多くの知識がエンコードされており、さらにデータを収集するだけで新しい知識を追加できることです。しかし、もう 1 つの利点は、データが大量になる可能性がある一方で、コードが簡潔であること
correct
です。ht://Dig のスペル コードの場合は 1,500 行を超えるのに対し、 は約 50 行です。...もう 1 つの問題は携帯性です。ラトビア語のスペル修正プログラムが必要な場合、英語のメタフォン ルールはほとんど役に立ちません。データ駆動型
correct
アルゴリズムを別の言語に移植するために必要なのは、ラトビア語の大規模なコーパスだけです。コードは変更されません。
彼は、Google で収集されたデータセットを使用して、Python のコードでこれを具体的に示しています。スペル修正に加えて、単語を分割し、暗号文を解読するためのコードがあります。Grady Booch の本は、数十ページを費やしても読み終えることができませんでした。
「The Unreasonable Effectiveness of Data」は、同じテーマをより広く展開していますが、基本的なことは一切ありません。
私は別の検索会社での仕事でこのアプローチを採用しましたが、テーブル駆動型/DSL プログラミングと比較してまだ十分に活用されていないと思います。
コードをデータとして扱える言語では問題ありません。ソリューションの必要に応じて、データ、コード、機能、OO、または手続き型に傾いて、明確で簡潔で保守可能なものを使用します。
手続き型では区別が明確であり、データを特定の方法で保存されたものと考える傾向がありますが、手続き型でもデータを API の背後、または OO のオブジェクトの背後に隠すことが最善です。
Alookup(avalue)
は、関数として開始される限り、その存続期間中にさまざまな方法で再実装できます。
...私は常に、存在しないマシン用のプログラムを設計し、次のように付け加えています。... 実際には、もちろん、この理想的なマシンは存在しないことが判明するため、次のタスクは、構造的に元のマシンと同様に、「上部」マシンのシミュレーションをプログラムすることです... しかし、これはプログラムの束はおそらく存在しないマシン用に書かれているので、次の仕事は、次の下位レベルのマシン用のプログラムの観点からそれをシミュレートすることです.私たちのハードウェア...
EW DijkstraのNotes on Structured Programming、1969 年、John Allenの引用、Anatomy of Lisp、1978 年。
私がかなり同意するこの哲学について考えるとき、最初に頭に浮かぶのはコード効率です。
私がコードを作成しているとき、それが常に完璧に近いものであるとは限らず、完全に知識があるとは限りません。必要なときにマシンを最大効率に近づけ、それ以外の時間は良好な効率を維持することを十分に知っているため (おそらく、より良いワークフローとのトレードオフ)、高品質の完成品を生産することができました。
データ駆動型の方法でコーディングすると、コードの目的のためにコードを使用することになります。すべての変数をファイルに「アウトソーシング」するのはばかげて極端です。プログラムの機能はプログラム内にある必要があり、コンテンツ、設定、およびその他の要素はプログラムによって管理できます。
これにより、より動的なアプリケーションと新機能も可能になります。
単純な形式のデータベースさえあれば、同じ機能を多くの状態に適用できます。また、すべてのデータが必ずしもファイル システムに保存されるわけではありませんが、ファイル ヘッダー データやディレクトリ、ファイル名、拡張子に基づいてプログラムが実行する内容のコンテキストを変更するなど、あらゆる種類の創造的なことを行うこともできます。
最後に、コードを単純にデータを処理する状態に保つことで、実際に何が起こっているかを想像することに近づく心の状態になります。これにより、コードがかさばらず、ブロートウェアが大幅に削減されます。
コードの保守性、柔軟性、効率性が向上すると信じており、気に入っています。
他の方もこの件についてご意見をお寄せいただきありがとうございます!とても励みになりました。