Golang Cafe #23 まとめ 「Twelve Go Best Practices」を摘要してみる

2014/03/30に開催された「Golang Cafe #23」についてのまとめです。
今回も+TakashiYokoyama氏が準備してくれたOAuthを使用したtwitter apiアクセスのサンプルコードを、前回までに勉強した「Twelve Go Best Practices」を元に最適化していくという内容でした。


当初の予定では準備されたコードを元にリファクタリング、最適化を進めていくということでしたが、
気がつけばスクラッチで書いたのではないかというコードになってしまいましたのでご了承ください。


手を入れたすべての内容を記載することはできないので、ポイントを絞って纏めておきます。
詳細な内容は実際のコードを読んでもらうのが一番かと思います。


私が修正したコード


今回準備されたコードはtwitterOAuth認証、認可を行い、APIを使用してtweetを行うものです。


今回の作業のポイントは以下のとおりかと思います。

  • OAuth1.0のメカニズムを理解する
  • 繰り返し書かれている冗長なコードを排除する
  • テスタブルなコードにする

OAuth1.0のメカニズムを理解する

今日ではOAuth2.0を採用するサイトが増えてきていますが、
TwitterではOAuth1.0が使用されています。

まずはこの仕組(処理の流れ)を理解しておかなくては始まりません。

細かな処理の手順は各サイトを参考にしていただくとして、
簡単に書いておくと以下の3ステップがあります。

  1. ConsumerKeyを用いて仮のOAuthTokenとOAuthTokenSecretを取得する。
  2. 取得したOAuthTokenを用いてブラウザで認可を取得する。
  3. 取得したPINコードを用いて正式なOAuthTokenとOAuthTokenSecretを取得する。


あとは毎回のリクエスト(キー交換時も)で使用されるoauth_signatureの生成方法を理解しておく必要もあります。

繰り返し書かれている冗長なコードを排除する

今回の最難関はoauth_signatureの生成です。
準備されたコードが冗長になっているのも、このoauth_signatureを生成する手順が複雑なためです。
これさえクリアできれば今回の作業の終ったに等しいです。


oauth_signatureの生成はリクエストごとに必要になるので、
これを生成するために必要なパラメータは内部で生成し、oauth_signatureを生成する処理を定義した構造体を作りました。
最低限必要なパラメータは構造体内で追加し、リクエストごとに追加で必要なパラメータは外部から設定できるようにしました。
さらにメソッド、URL、送信値を設定するようにしました。

実際の処理はリクエストで必要になるoauth_signatureを含んだAuthorizationヘッダを作成するようにしました。

テスタブルなコードにする

一番の難関であるoauth_signatureの生成についてのみテストコードを書きました。
入力値と期待値はtwitterのサイトにあるものを使用します。

テストを作成する上で2つの難所がありました。

  • oauth_timestampに時刻を使用している
  • oauth_nonceに乱数を使用している

実行するたびにこれらの値は変わってしまうので、如何にしてテストの時のみ固定値を使用するようにするかということです。

テスト時のみoauth_timestampとoauth_nonceに使用する値を構造体の外部から設定できれば良いので、Setterを用意しても良さそうでしたがoauth_timestampとoauth_nonceの値を生成する処理を外部で定義する方法を取りました。
方法は2つ思いつきました。

  • 値を生成する関数型のフィールドを用意して、外部でその関数を実装する
  • 値を生成するメソッドを持つinterfaceのフィールドを用意して、外部でそのinterfaceを実装した構造体のインスタンスを設定する

今回は前者の方法でテストを実装しました。
oauth_signatureの生成に必要なデフォルトのパラメータもSetParamメソッドを使用して外部から指定できるようにしました。
テスト時には

g.SetParam("oauth_nonce", "kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg")
g.SetParam("oauth_timestamp", "1318622958")

のようにすれば指定した値が使用され、未指定の場合は既定の計算方法にて算出するようにしました。

まとめ

最初にも書きましたが、今回は非常の文章でまとめにくい内容で、準備されたコードと私の作成したコードを比較して読んでもらうのが一番かと思います。
うまくまとめられなくてすいません。
OAuthの処理はできるだけ汎用的に書いたつもりですが、まだtwitterに依存する部分があるのもまだまだ改善の余地はありそうです。
また「Twelve Go Best Practices」に忠実にしたがって書けたかどうかも疑問です。
(最初のコードよりは見通しが良くなっているとは思いますが)