式チェーンが長い場合は、を使用してlet
ください。長い暴走式や深くネストされた式は、どの言語でも特に読みやすくはありません。これは悪いです:
(do-something (map :id (filter #(> (:age %) 19) (fetch-data :people))))
これはわずかに優れています:
(do-something (map :id
(filter #(> (:age %) 19)
(fetch-data :people))))
しかし、これも悪いことです。
fetch_data(:people).select{|x| x.age > 19}.map{|x| x.id}.do_something
これを読んでいる場合、何を知る必要がありますか?do_something
のサブセットのいくつかの属性を呼び出していますpeople
。このコードは、最初と最後の間に非常に距離があり、それらの間を移動するまでに見ているものを忘れてしまうため、読みにくいです。
Rubyの場合、do_something
(または最終結果を生成しているものは)行の最後で失われるため、に何をしているのかを判断するのは困難ですpeople
。Clojureの場合、それが私たちが行っていることはすぐにわかりdo-something
ますが、すべてを内部まで読んでいなければ、私たちが何をしているのかを判断するのは困難です。
この単純な例よりも複雑なコードは、かなり苦痛になります。すべてのコードがこのように見える場合、これらのスパゲッティのすべての行を前後にスキャンするのに首が疲れます。
私はこのようなものを好みます:
(let [people (fetch-data :people)
adults (filter #(> (:age %) 19) people)
ids (map :id adults)]
(do-something ids))
今では明らかです:私は最初にpeople
、私はぐるぐる回って、それから私do-something
は彼らに行きます。
そして、あなたはこれで逃げるかもしれません:
fetch_data(:people).select{|x|
x.age > 19
}.map{|x|
x.id
}.do_something
しかし、少なくともこれを実行したいと思います。
adults = fetch_data(:people).select{|x| x.age > 19}
do_something( adults.map{|x| x.id} )
またlet
、中間表現に適切な名前がない場合でも、使用することは前例のないことではありません。(このスタイルは、Clojure自身のソースコードで使用されることがあります。たとえば、のソースコードdefmacro
)
(let [x (complex-expr-1 x)
x (complex-expr-2 x)
x (complex-expr-3 x)
...
x (complex-expr-n x)]
(do-something x))
これは、デバッグにおいて大きな助けになる可能性があります。これは、次のようにすることでいつでも物事を検査できるためです。
(let [x (complex-expr-1 x)
x (complex-expr-2 x)
_ (prn x)
x (complex-expr-3 x)
...
x (complex-expr-n x)]
(do-something x))