“Clojureライブラリ・コーディング規約” まとめ
In: Clojure
13
2月
2010
前エントリ
clojure.lib コーディング規約・訳
から1週間以上がすぎました。
Google Groupsでのディスカッションで合意されたコーディング規約をStuがまとめてアップしてくれました。
Clojure Library Coding Standards | Clojure | Assembla
さっそく和訳してみました。
間違いがあればご指摘ねがいます。
⇒ @manjilab
【和訳ここから】
免責事項:
- 規則は破られるためにあります。この規約に倣うも絶対のものとして扱わないこと。
規約:
- 名前と使用法はよく考えて書くこと。RichはJavaにおける既存のコードとの互換性の維持を尊重しています。練習用のコードであればいつまでもいじってられますが、ひとたび名前と使用法が公開されればそうはいきません。(具体的な実装に興味がなく名前と用法だけを見ている利用者が多いですから)
- コードの重要そうな関数には型ヒントをつける。もしくは型情報なしでも簡潔なコードに。
- 本当に必要なものにだけ型ヒントをつける。そうであると確信が持てないのであればつけない。
- 良い名前をつける。他の名前空間のものとの衝突を恐れない。そのための名前空間。
- とはいえ用法や意味が違うものを同じ名前で使う場合は、その中にふさわしくないものがないかどうかをよく検討すること。
- パッケージ依存は明確・最低限に。(useやrequireをする時には :onlyオプションを使う)
- 関数で実現できる場合はマクロは使わない。マクロの方が使い勝手が良い場
合は関数版も合わせて提供すること。(未決の問題:命名規則は必要? “foo” と “foo*”が多く使われてるけど)
- コンパイル時にすべての情報がわかっているのであれば、パフォーマンス上有効な部分にマクロを使う。(ログのためのマクロの議論を参考。結局両方のバージョンが必要となった。コンパイル時に完全な情報が得られないケースが多いからだ。)
- ライブラリレベルで docstringを書くこと。
- 全関数に対して自動化されたテストを書くこと。
- オプションの引数は展開すること。呼び出し側がオプション引数をマップで包まなくてもいいように。
- (release-sharks 2 :laser-beams true) ; 良い
- (release-sharks 2 {:laser-beams true}) ; 悪い
- 述語の名前は最後に ? をつける。
- docstringをつける。例外として、関数がの定義が明白そのものでdocstringが関数名と引数をただ冗長に示すだけのような場合は書かない。(私もそれに該当するdocstringは削除する方針にした。)
- これはHTMLドキュメント化のようなツールにとってマイナス?
- 迷ったら性能のよい方を公開すること。Clojureは求められるパフォーマンスを提供すべきであり、ライブラリも同じです。(それがマルチメソッド版の + をcoreでは提供していない理由です。)ユーザは必要に応じてAPIをハイジャックして新たな型を作ることが出来るのですから。
- よい名前を使いたいけどcoreと衝突するような場合は意味が同等になるように心がけてください。coreのシーケンス関数に対する文字列処理関数が良い例となるでしょう。
- assertや pre- post-などの条件処理を気軽に使いましょう。現時点ではあまり使われていませんが、もっと使われるべきです。#250を参考。
- できるだけ遅延評価で書きましょう。
- 変数名は pred や coll のように clojure.coreの慣例に従うこと。
- clojure.coreの起動初期コードの慣用表記に倣ってはいけない。それらはClojureが立ち上がる前の限定された環境のために書かれているから。
- コードを小さい塊に分割せよ。doseqの定義のような書式はRich以外の人は書かないで。
- オブジェクトの要素へのアクセスはキーワードを先にもってくる。
- (:property object-like-map)
- コレクションから値を取り出すときはコレクションを先にもってくる(コレクションがnilかもしれない場合にはgetを使う)
- (collection-like-map key) (get collection-like-map key)
- すべてのコレクションがキーワードをキーとして持つわけではないので注意。
- 分配束縛はよく用いられる。しかし渡された値の一部を使いたいときには引数書式の所での使用にどめるべきだ。もしくはletの最初の行で。Programming Clojureに載せたスネークゲームのコードはこれに反しているけれど。
- トランザクションではセットよりも更新を使おう。統一的な更新モデルはもっとも基本的な方法であり、交換可能な処理を発見しやすくなる。それにより更新処理の衝突を少なくできる。
- 想定していないコレクション型をサポートしてはいけない。アルゴリズムがランダムアクセスを用いるのであれば、受け取る型はランダムアクセス可である必要がある。
- *earmuffs* は再束縛を意図するものにのみ使用する。
- bang! はSTMトランザクションで安全でないものにのみ使用する。
- loop/recurよりもシーケンス・ライブラリの組み合わせを用いる。
- varの再束縛にはスコープ系マクロをいっしょに。例)*in* と with-in-str
- 遅延シーケンスは最小限の状態を持つ関数として書く。つまり「頭をかかえない」こと。どの程度の規模で現実化するかは呼び出し側にまかせること。
- interop は Klass/staticField, (Klass/staticMethod), (Klass.), (.method obj) の型式で。例外はコードを生成するコード中で(. obj method)の方が簡単な場合のみ。
- 引数の順序はよく考えて。ライブラリのなかでは一貫性を持たせること。
- パラメータを動的束縛で暗に受け渡すインターフェイスを提供している場合(例: sqlにおけるdb)、パラメータを明確に受け渡せるインターフェイスも合わせて提供する。
【和訳ここまで】