今手を焼いているコードには名前から動作を推測できない関数が多い。関数の動作はなんとなく想像できたとしても、引数の意味が不明だったりする。特に多いのが引数や戻り値が2通りの値を取る場合に、安直に型を bool にしている箇所。
例えば、
void Set_Gain(bool bGain); bool GetIntOrExt(void); ... Set_Gain(true); //tureを渡すと何が起こる? ... if (GetIntOrExt()) { //IntOrExt が true ってどういう意味? ... }
のような関数だ。
Set_Gain() は増幅回路を設定する関数のようだが、引数にtrueを渡すと何が起こるのだろうか?
一方の IntOrExt() は、何らかの信号源が内部(Int)か外部(Ext)のどちらに設定されているかを返す関数のようだが何の設定を返すのだろうか?それに、trueとfalseはIntの時とExtの時のどちらに対応しているのか?
コメントの類は一切無かったので、ホスト側のソースから順にたどって、最終的に通信相手の機器のファームウェアのソースまで確認するはめになった。
結果的に、実際の動作はこういうことだった
/*! @brief 機器の増幅回路をON/OFFする @param[in] bGain true=増幅OFF、false=増幅ON */ void Set_Gain(bool bGain); /*! @brief 装置の発振回路が内蔵か外付けかを判別する @retval true 内蔵(Internal) @retval false 外付け(External) bool GetIntOrExt(void);
Set_Gain() に true を渡すと増幅回路がONになると予想していたが、実際はその逆で true で回路がOFFになる。増幅回路の切り替えロジックが負論理で作られていることで、このような不自然な仕様になっているようだ。つまり回路の構造が隠蔽されることなくファームウェアからパソコン上のGUIまで直通しているということになる。ここにはインターフェースを意識して設計するという姿勢は見られない。
こういう動作をする関数ならせめて次のような名前にして欲しかった。
/*! @brief 機器の増幅回路をONする */ void EnableGainCircuit(bool bEnable); /*! @brief 装置の発振源が内蔵発振器かどうかを判別する */ bool GetIsInternalOscillator(void) const;
これなら true/false の意味が明確になる。
もっとも自分なら enum を使って以下のように書く。
/*! @brief 機器の増幅回路をON/OFFする @param[in] bGain LOW=増幅OFF、HIGH=増幅ON */ typedef enum { LOW, HIGH } GAIN_LEVEL; void Set_Gain(GAIN_LEVEL GainLevel); /*! @brief 装置の発振源が内蔵か外付けかを判別する @retval INTERNAL 内蔵 @retval EXTERNAL 外付け */ typedef enum { INTERNAL, EXTERNAL } OSC_SOURCE; OSC_SOURCE GetOscillatorSource(void) const;