構文糖の危険性

何言ってるの? もちろん、構文糖を使用しても構文糖尿病につながることはありませんが、考えることを止めることができます。 直感的なラッパーで抽象化の操作をラップし、プログラムを読みやすく、単純にキュートにするために、構文糖が私たちの生活を楽にするように設計されていることを考えると、これは奇妙に聞こえるかもしれません。 しかし、私たちの思考を導くツールは、同時にその方向にそれを保持します。



ここでの状況は、アメリカ人が誇る道路に関する冗談のようなものです。

-道路に沿って運転するときは、フードにコップ1杯の水を置き、時速100 kmで運転します。 一滴も水がこぼれません。

ロシア人の言うこと:

-そして、私たちは皆、後部座席に登ってカードをずっと切りましたが、ビールを飲みます。

-そして、誰が機械を制御しますか?!..

-しかし、彼女は一体どこに行くのか?



おもしろいですが、快適ですが、シンタックスシュガーがなかったら、後部座席にいる人たちもenましく思います。 トラックは、あなたが運転する方法について考えることができないという点で優れています、構文糖は、あなたが書く方法について考えることができないようにし、タスクに集中するために脳を解放します。 しかし、問題を解決するために奇妙なことをする必要がある場合はどうなりますか? 軌道に乗る? 問題は、そこから抜け出すのが難しいということではなく、それが私たちの考えのruだということです。他の方法があることは、私たちにはまったく起こりません。



しかし、十分な理論、それはあなたの手を汚す時です。 例を挙げましょう。 ORMを作成し、ある時点で、たとえばSQLクエリを作成するために、モデルフィールド名のリストを取得する必要があるとします。 また、フィールドは、フィールドの名前を含む名前プロパティを持つオブジェクトであると仮定します。 ただのビジネス! すべてのフィールドを調べ、名前を引き出してリストを作成するだけです。

var names = [];

for ( var i = 0 , l = fields.length; i < l; i ++ ) {

names.push(fields[i].name);

}





私たちはJavaScriptでORMを書いているように見えますが、最近では、人々はもっと奇妙なことをしています。 ところで、最初の構文トラップに陥りました-ループとして解釈され、その結果、いくつかの変数、整数の比較、増分、角括弧が得られました。 くそー! これは、「走りに行く」と言ったとき、私が念頭に置いていたものではありません! もう一度試してみましょう。

var names = fields.map( function (field) {

return field.name;

});





要するに、よりきれいで、アルゴリズムを説明した方法にずっと近い:フィールドを通過する-fields.map、名前を取得する-名前を取得する関数。 N-yes、関数、それを取り除く方法は? 簡単です、私たちは自分自身を制限しません、私たちはPythonですべてを書き直します:

names = [field . name for field in fields]





一行! 理想に達したように見えますが、実際には、このオプションは以前のオプションよりもさらに悪い点がいくつかあります。拡張することは難しく、再利用することはほとんど不可能です。 うん 試してみましょう、フィールド名の前にテーブルにエイリアスを時々割り当てる必要があったとしましょう:

names = [ " %s . %s " % (alias, field . name) if alias

else field . name for field in fields]





もうそれほどクールに見えませんが、フィールドにエイリアスを割り当てる必要がある場合はどうでしょうか? そして、結局のところ、これは必要ではなく、他の何かです。 コードが制御不能になるのを待たず、予防的にリファクタリングします。

if alias:

names = [ " %s . %s " % (alias, field . name) for field in fields]

else :

names = [field . name for field in fields]





明瞭さは戻ったが、重複が現れた。 使用するリスト式が単一の構文構造内でリンクし、別の要素に対する実行と操作をリンクすることは偶然ではありません。 問題ではなく、リスト式を1つだけ残してください。

if alias:

get_name = lambda field: " %s . %s " % (alias, field . name)

else :

get_name = lambda field: field . name

names = map (get_name, fields)





...または単一ではない-実行と操作の混乱を取り除くとすぐに、リスト式は不要になりました。 ここにもう1つ興味深い点があります。javascriptの内容に戻りました。 つまり、言語にリスト式などの甘い要素がないため、より普遍的なコードを書くことになりました。 これは「より少ない」仲間の良い例ですか?



したがって、私はforループとpythonicリスト式を「削除」します。次は先に進みます。 ドットを介してオブジェクトのプロパティにアクセスしますか? 私にとって-これは非常に短く(オブジェクト自体と必要なプロパティを除いて、小さな点のみがあります)、表現力があります(オブジェクトから遠く離れた人でも塩が何であるかを簡単に理解できます)。 とても便利なので、他の方法については考えません。同じpythonで、オブジェクトの属性を取得する3つの方法があります(__getattr__への直接アクセスなど。根本的に新しいものを与えないチート):

obj . name

getattr (obj, "name" )

operator . attrgetter( "name" )(obj)





属性にアクセスする操作を関数に変換するため、最後の最も気味の悪いオプションに興味があります。 ラムダを使用してエミュレートするもの。 これが属性を取得する唯一の方法である場合、すぐに普遍的で拡張可能で再利用可能なコードを作成します。

from operator import attrgetter

names = map (attrgetter( "name" ), fields)







私は構文を放棄することを提案しているように見えるかもしれません-いいえ、これはほとんどの現代言語の重要な部分であり、コードの読みやすさと表現力を保証します。 最後に、私はコードを適度に甘くすることも気にしません。 私が言いたいのは、構文の背後にあなたがしていることの本質を見て、コードがタスクを表現し、タスクの個々の部分が別々の構文要素にあるように構文をプッシュできるようにすることが重要だということです。



PS私はJavaScriptでORMを書きません。

PPS私はpythonでORMも書きませんが、時々ORM Djangoを掘り下げます。

PPPSここで紹介し奇妙なアイデアは、Practical Common Lispを読んでいるときに思いついたものです。 知らない人のために、Lispプログラムはネストされたリストのセットであり、それぞれが「すること」(関数名、演算子またはマクロ)とそれに続く引数、つまり 自身の構文ツリーを表します。 言い換えれば、Lispには構文はありません。 そして奇妙なことに、これによりプログラムは驚くほど柔軟になります。



更新 反対意見のほとんどに答えるために、少し違った方法で考えます。 最終的に使用するmap()もかなり高レベルの抽象化であることに注意してください。 実際、私が使用する抽象化は階層に配置できます。

Cスタイルの+インデックス作成からの抽象化= for-in

for-in +各反復で結果を返す= map

マップ+ラムダ=リスト式。



低レベルから始めて、私がやろうとしていることを最もよく表す抽象化のレベルに到達します。 そして、一般化する必要がない場合はここで停止する必要がありますが、一般化する必要がある場合、リスト式は1つのボトルのマップとラムダであるか、コードの複製を開始することを覚えておく必要があります。 (jsのように)言語にリスト式がない場合、すぐに一般化されたコードを受け取りますが、それは下位レベルになります。 リスト式が壊れている可能性があることを忘れた場合、コードの複製を開始します。



要約すると:

1.言語に特定の構文がないため、より柔軟なコードを記述できます。

2.このより柔軟なコードは、より低いレベルになります。



最初の2番目の料金、

from operator import attrgetter

names = map (attrgetter( "name" ), fields)





-ポイントがある場合、時期尚早の一般化。



All Articles