サンプルとなるライブラリはそこらにあるし、ネットで検索するといろいろと情報は出てくるが、そもそもというところがわからなかった。
これはArduinoスタイルでAPIライブラリを作成するためのスタイルガイドである。ここに書かれているいくつかのことはプロフェッショナルなプログラミング実践とは相反している。多くの初心者がArduinoを簡単に始められるために、あえてそうしてある。これらの原則に留意してライブラリを作成してほしい。ArduinoライブラリをArduinoユーザにとってよりわかりやすいものにするための提案があれば、ディスカッションに加わって欲しい。まだArduinoライブラリは進行中のプロジェクトである。
- エンドユーザにわかりやすく:聡明だがプログラミングの経験のない人がこのAPIを使うと想定する。APIが扱う概念について、わかりやすいメンタルモデル、用語や関数を考え出すこと。
- APIを、表面に出ていない拡張性にマッチさせる:詳細な実装は隠したいとしても、APIの拡張性について不正確なメンタルモデルを与えるべきでもない。例えばある設定に対していくつかの選択肢しかない場合に、int型の引数をとる関数を使うべきではない。それは好きな値を設定できると意味していることになる。
- ユーザが使いたいデータと機能に沿った公開関数セットを提供する:特定の電子モジュールを扱うコマンドセットが、通常に使用するにはあまりにも複雑で、高レベル関数などにまとめることができるということは非常にありがちである。一般のユーザが考えることについて考え、それに沿ってAPI関数セットを提供するよう心がけること。AdafruitのBMP085ライブラリはよい例である。readPressure()コマンドは最終結果の圧力を得るために必要なすべてのステップを行う。このライブラリは何度も実行される一連の関数を一つの高レベルコマンドにラップし、そのコマンドはユーザが得たい値をユーザが望むフォーマットで返す。このコマンドは低レベルI2Cコマンドだけでなく、中間レベルの温度や圧力の計算も抽象化している。その一方でこれらの中間レベルの関数も、それを望むユーザに対して提供している。
- 省略しない日常語を使う: 関数名や変数名に説明不足な言葉を使わないこと。技術用語の代わりに日常語を使うこと。APIが扱う概念の、一般的で親しみのある見識に対応する言葉を選ぶこと。専門知識を前提としないこと。我々がpwm()ではなくanalogWrite()を使ったのはこの理由からである。略語は使ってもよい、ただし、それらが一般的に使われているか、何かの基本的な名前である場合に限ってである。例えば、"HTML"は比較的に一般的であるし、"SPI"はプロトコルの名前として有効である。("serial-peripheral interface"はおそらく長すぎる、“Wire”はおそらく間違いだった、このプロトコルについては通常"TWI"や"I2C"と呼ばれる)
- 一般の人にとって異なる意味を持つ言葉を避ける:例えばプログラマにとってはerrorは何かが起こった通知であるが、一般の人にとっては悪いことになる。
- ある分野に特有の用語を使う必要がある場合には、「先に」一般の人に対する1〜2文の説明を書く:よりよい言葉を思いつくか、それができなければライブラリのドキュメントを作成する。
- ドキュメントとコメントを書く:サンプルやドキュメントを書く際には以下のスタイルガイドに従うこと http://arduino.cc/en/Reference/StyleGuide
- 実績あるcoreライブラリやスタイルを使うこと:
- 入力を読むにはread()を使い、出力するにはwrite()を使う。例:digitalRead(), analogWrite(), 他
- バイトストリームを扱う場合にはStream.hとPrint.hライブラリを使う。それらに適合しない場合でも、最低限モデルとしてこれらのAPIを使えないか検討すること。詳細は後述する。
- ネットワークアプリケーションについては、原則としてClientとServerライブラリを使う。
- ライブラリインスタンスを初期化するにはbegin()を、通常いくつかの設定とともに使い、終了するにはend()を使う。
- 関数名にはキャメルケースを使い、アンダースコアは使わない:例えばanalog_readではなくanalogReadとする。またmy_new_functionではなくmyNewFunctionとする。これは可読性を重視してProcessing.orgから取り入れた。
- LONG_CONSTANT_NAMES_FULL_OF_CAPSのようなものは読みにくい:可能であればシンプルに、ただし説明不足にならないようにする。
- ブーリアン引数は避ける:代わりに2つの関数を、その引数による動作の違いを表す名前をつけて提供できないか検討する。
- ポインタの知識を前提としない:Cの初心者にとってポインタは最大の障壁であるし、&や*をみてもわけがわからないものである。したがってAPIにポインタを導入しなくてすむのなら、そうすべきである。一つの方法としては*ではなく配列で参照渡しをすることである。例えば
void printArray( char* array);
は次のようにできる。
void printArray(char[] array);
いくつかのライブラリではライブラリ側からconst charのようなポインタを渡すものがあるが、ユーザ側がポインタを渡すことは避けること。例えば、
foo.readAccel(&x, &y, &z);
よりは以下のようにすべきである。
xAxis = adxl.readX();
yAxis = adxl.readY();
zAxis = adxl.readZ();
シリアル通信を使う場合、Serialオブジェクトをハードコーディングするのではなく、ユーザがどんなStreamオブジェクトでも指定できるようにすること。これによってライブラリはMegaやDueのすべてのシリアルポートで使えるようになるし、SoftwareSerialのような別のインタフェースを扱うこともできる。ライブラリのコンストラクタかbegin()関数にStreamオブジェクトを渡すようにすればよい(ポインタではなく参照で)。それぞれの例として
Firmata 2.3や
XBee 0.4を参照のこと。
バイトストリーム通信を行うライブラリを作成する場合にはArduinoのStreamクラスを継承すること。そうすればそのライブラリは、Streamオブジェクトを扱える他のすべてのライブラリから使うことができる。可能であれば入力バッファはread()がすぐにデータにアクセスできるようにし、続きのデータの到着を待たないようにする。可能であればwrite()メソッドはデータを送信バッファに保存するが、バッファに空きがない場合にはバッファが空くまで待たなければならない。待っている間にはyield()関数を呼ぶべきである。
これはWire (I2) ライブラリをうまく抽象化している例である。
https://github.com/adafruit/RTClib Reference Home訂正や提案、ドキュメントの追加は
フォーラムに投稿してほしい。
※本文書はオリジナルと同様、
Creative Commons Attribution-ShareAlike 3.0 Licenseに従います。