Google Tag Managerが思ってたより便利そうだ

広告を含めたコンテンツ運用系ぽい人たちから聞こえるだけは聞こえてたけどこれまで関わってこなかった Google Tag Manager を触る機会を得たのでその実例と感想など。

まとめ

Google Tag Manager を使うと

  • プログラムコードで何もせずに Google Analytics の Property ID の切り替えを行うことができて便利
    • つまり静的サイトでも切り替え可能
  • タグの設定を publish してしまう前に関係者だけで preview できて便利
  • publish したあとに rollback もできて便利

やりたいこと

Google Analytics に staging 環境が欲しい。そんでいい具合に切り替わってほしい。

これ。

なぜstaging環境が欲しいのか

Google Analytics のトラッキングコードだけの話ではないんだけど、development や staging へのアクセス、検証作業によって本番用のデータにノイズが乗ってしまうのは望ましくない。DB の登録内容は本番とテストで分けるのに Google Analytics のデータは混ざったままにしてしまうのはいかがなものか。

PV しか採っていない場合はまぁそれでも影響は軽微かもしれないけどね。変わったイベントを捕捉したい、みたいな場合は開発時にたんまりイベントを Fire してしまうのでかなりタチが悪くなってしまう。

もちろん、コードの作り方や Google Analytics 上のフィルタ設定などでノイズを後から取り除くことができる場合もある。しかしその場合はフィルタ設定できる人やフィルタを適用したビューを正しく選ぶことのできる人でないと正しいデータを手に入れることはできない。変なところで属人化してしまう可能性が高い。

これまでのやり方

ということで、こういった欲しくないデータが混入してしまわないように、これまではプログラムコードのちょっとした工夫で property を切り替えていた。

AnalyticsHelper のようなものを用意して

def ga_property_id
  if ENV['GA_PROPERTY_ID']
    ENV['GA_PROPERTY_ID']
  elsif Rails.env.production?
    'UA-xxxx'
  elsif Rails.env.staging?
    'UA-xxxx'
  end
end

こんなコードを書いて HTML の中に埋め込んでおいて、Google Analytics の初期化処理の中で DOM の中の Property ID をセットする。

ga('create', 動的に作る)

ちゃんと環境を判別できるように作ってあって deploy が自動化されていれば特にあれこれ気にすることなく以下の状態を再現できていた。

  • 通常の開発ではわざわざ Google Analytics にリクエストを飛ばさないように
  • staging で確認する際も余計なアクセスが記録される心配がない
  • Analytics 関係のコード(イベントトラッキングとか)を開発する時は必要に応じて Property ID をセット

これはこれでなかなかよかった。

少なくとも本番用の Google Analytics トラッキングコード埋めっぱなしよりははるかに。

Google Tag Managerを使ったやり方

Google Tag Manager の基本的な設定方法などは省略。特別難しいことはないので、ちょっと Web に詳しい人なら画面の指示に従ってそのまま作業するだけでよいはず。概略などもぐぐればぞろぞろ紹介記事が出てくるのでそちらに譲ります。

今回の設定に関係してくるものは大きく2つ。

  • Tag
  • Trigger

Tag は今回の例で言えば Universal Analytics Tag になる。これに Property ID をセットしてやれば Google Analytics のトラッキングコードをペタッと貼ったのと同じ状態を再現できる。

ここにおもむろに staging 用の ID でもう一つ Universal Analytics Tag を追加する。このままでは両方に記録されてしまうが、それぞれに Trigger を設定することで片方ずつ適用されるようにできる。

production 用の property の方は Page View を All Pages ではなく Page Hostname に production のホスト名が入っている場合に Fire することにしておく。逆に staging 用の property の方は Exception で production のホスト名を含む場合を設定しておく。

これで Google Tag Manager を使って Google Analytics の production 用の property と staging 用の property の切り替えを、一切コードを書かずに実現できる。

この方法を使えばサーバサイドのコードは必要ないので、静的サイトでも切り替えを実現できる。

感想

今回、この設定を試すに当たり、意外にワークフローが考えられていて優秀だなと思った。(失礼)

というのも、従来のコードで切り替える方法では、コードの deploy と property の切り替えは同時に起きてしまうので、少なくとも切り替えのコードを初めて適用するときは deploy したらすぐに「リアルタイム」で確認を行うようにしていた。これが Google Tag Manager では publish の前に preview を行い、その状態で「リアルタイム」で確認することができる。

preview というのは Google Tag Manager にログインしているブラウザでのみ、これから適用しようとしている Tag Manager の設定が反映されるものだ。おまけに該当するブラウザでは特に何もすることなくどんな Tag が設定されているのか、その Trigger は何か、みたいな情報を確認できる。例えばこれで Tag Manager へログインしている複数の人でどのような Tag が反映されるのかをリリース前にチェックすることができる。これはかなり安心だ。

さらに publish は名前を付けて保存され、その履歴をたどることも rollback することもできる。1プログラムコードでやっているようなバージョン管理と rollback を Tag Manager 上で再現できるので、Google Analytics 単体で設定を頑張るよりもよほど安心だと思った。

他にもイベントトラッキングも Tag Manager から設定できる2し、もちろん広告など他のタグも利用できる。こうしたタグの追加も、プログラムコード上は最初のコードスニペットから何ら変更する必要はないし、例えば広告は development や staging では表示しないといったことも、上の GA の property 切り替えと同様に可能だ。

今回は時間の都合で自分が Tag Manager を触ることになったが、確かにこれは非エンジニアがエンジニアを頼らずにいろいろなことができる、非常に優れたツールだなと感じた。これまでは「いやいや、うちみたいに Property ID の切り替えとかちょっと変わったことやってるところは逆に困らない?」って思ってたけど、あっさり上回ってくれることが分かったし、何より面白いと思ったのは

非エンジニアの方が多く触るであろうツールに、エンジニアの世界では当たり前のバージョン管理とロールバックの概念を持ち込んでくれていること

である。これ、ガンガン積極的に布教していったら、ディレクター、運用方面とエンジニアの文化のギャップが少しは減るんじゃないかなぁ。

おまけ

「広告のコンバージョンタグ」って何かと思ってたけど、こういうのも Tag Manager 上から管理するようにすると Google Analytics の設定と AdWords の設定と…ってバラつかずに便利っぽい。やることは結局 URL にマッチするパターンを作ることだけなので。

  1. ちょうど Google Apps Script のリリース周りの設計のような感じ。 

  2. 細かい要素やイベントの制御のためにはやはりコードを書いた方がよいと思う。上の設定で staging との分離はできているので、安心してコードを書ける。 

OOの原則とテストのための原則破り

を読んでいます。で、まぁいろいろ Twitter の方には流しているわけですが、とりあえず

テスト用のクラスで本番コードと一部挙動を変えてしまう

という、これまでの自分にはなかった発想が書かれていたので試しに PHP で書いてみました。

Singleton を Singleton じゃなくしてテストする

テスティングフレームワークは今は亡き pearified.com の SimpleTest を使っているのでその辺は適宜書き換え、読み替えてください。

ここでは

Singleton なクラスをテストのときだけ様々なパターンでインスタンス生成したい

ケースを想定しています。実際、よくあると思います。そのために

  1. コンストラクタの可視性を変更し
  2. instance() メソッドの戻り値を変更

しています。

どちらかだけで「本当は Singleton なんだけどテストのときだけ普通のクラス」という状態を実現できます。

1 の場合はたまたまコンストラクタですが、同じ要領でテストのときだけメソッドを public にしてテストすることができます。まぁ今回のケースのように「中身がなくて可視性を変えるだけ」であれば簡単ですが、普段はあまりやらないかも。それよりも

どうしても直接テストしたいメソッドは public にする

という方法の方がラクチンだし確実ですね。

2 は本当はメソッドの挙動が変わってしまう(何回呼んでも同じ値が返ってくるわけではない)ので、リスコフの置換原則には反しているような気がします。でもこれも有効なテストのための手法の一つだなぁと思います。Singleton じゃない場合でも

依存オブジェクトの生成処理がメソッドの中にあればオーバーライドして Fake オブジェクトを作るのが容易になります。

そうすると簡単に依存性を排除できます。

cf.

PHP: spl_object_hash - Manual

PHP 5.2.0 以降ではオブジェクトの同一性をハッシュ値で確認できます。

何が大事なことなのか

今回やったことは、恐らく OO の大きなメリットの一つであるカプセル化に反しています。また恐らくリスコフの置換原則にも反しているんじゃないかと思います。しかし、おかげでテストが書きやすくなり、コードの挙動をコードで記述し、捕捉することが可能になり、コードが理解しやすくなり、結果、ソフトウェアのメンテナンス性は上がります。

カプセル化とテストによる保護は必ずしも対立しませんが、それらが対立する場合、私はテストによる保護を優先します。そのほうが、将来カプセル化を強めるために役立つことが多いからです。

カプセル化はそれ自体が目的ではありません。それは理解するための手段です。

(『レガシーコード改善ガイド』 初版第2刷 p186)

本当に大事なことは盲目的に OO の教義に従うことではなくて、より良い品質のソフトウェアを書き、その価値を届けることなわけで、OO の教義も今回の原則違反もそのための手段なんですよね。

もしかすると TDD の本やリファクタリングなんかにはこの手のことがすでに書かれているのかもしれませんが、目から鱗でした。どんどん活かしていこうと思います。

cf.

要はどこでツッパるかってことなのでは?

※ 今回は割といろいろ読みました。

今回の話ってマシン語という単語だけ抜き出しても賛否にレベルがいくつもあって、

  1. マシン語なんて今どきムダ
  2. 教養としてマシン語の習得はしておいた方がよい、あるいはマシン語をやっといて損はないよ
  3. 絶対マシン語は習得しておくべき
  4. 絶対マシン語を現場で使えるべき

くらいに分かれています。そのうえで回路がどうのという話、機械の振る舞いがどうのという話にまで膨らんじゃってる。まぁ噛み合うわけがないわけで。ところでこの 3 と 4 にはものすごい差があると思うんだけど、みんなどの辺のレベルでマシン語が必要って言ってるんだろうなぁ。ちなみにぼくは CASL くらいしかまともに動かしたことのないお子ちゃまだよ。1

これが例えば果てしなく上のレベルを求められたらみんなどうなのよ、と疑問を投げかけてみる。ヒューマンスキル、ビジネスロジック、モデリングをすべてのプログラマが求められたらそりゃそんなのおめぇネクタイ締めてる SE の仕事だろべらんめぇ、って思わないかい? 思うよね?

それと同じ気持ち悪さを上のレイヤーで仕事してるプログラマは感じてるわけですよ、今回の話って。たぶんですけど。

ただ今回、あぁそうかもなぁと思ったことが一つあって。上のレイヤーで仕事しててもオープンソースじゃない製品の相手をしなくちゃいけない場合は、マシン語レベルのノウハウは役に立つかもというか必須となるシーンは出てくるかもな、ということ。

オープンソース脳になってると、とにかくプロダクトの中を覗けるのが当たり前だから、いきなりマシン語の話が出てくるとはぁ?って思っちゃうけど、中身分かんない場合はマシン語っつーかバイナリのパターン以外に判断材料なかったりするから、マシン語云々ということではなくバイナリアンとしての体力は絶対あった方がいいと思う。

というかまさにそこ自分で苦手に感じてるところで、具体的に言うと MS 製品とかになっちゃいますけど、要は仕様として明記されてないから自分で動かして調べていかないと最終的な挙動をはっきり定義できないとか、逆に仕様には書いてあるのに実現できてないとかそういう問題を見つけても、とりあえずサポートに丸投げするしか方法がないわけです。つか追っかけてるヒマが絶対ないって分かってるから丸投げできるプロプラ製品を買うわけですけど、それ全否定されるとさすがに困っちゃうね。

話がそれた。

で、丸投げって書いたけど、いろいろ条件変えてテストしてそのレポートは送ってるわけです。最終的にサポートでも再現できて、かつごめんなさいと言われました。再現はできるけど根本的な解決策は現段階では存在しないと。ここまでの過程においてはマシン語の知識はまったく不要なんですけど、これが「この製品」を使ったサービスをお客様に提供しますということになると、サポートにごめんなさいと言われて諦められるかっちゅーとそれは違うかもなとは思います。

伝わりますかねぇ。我々比較的上のレイヤーで勝負する人間はこのとき、「この製品」以外の選択肢をまず模索します。サービスが商品なのであって、「この製品」は代替可能であるべきと考えているからです。そこはツッパるところじゃない、と。でも「この製品」に縛りを加える要素が2あるのであれば、上のレイヤーの人間であってもツッパらなくてはいけないかもしれません。

要するに

  • まず何を実現しなければいけないのか?
  • そのために必要な技術要素は何か?
  • この技術要素に「問題」が発生したときにどのレベルに下りなければいけないのか?

を判断したうえで、マシン語が必要ならそれは本当に現場で必要なマシン語の話3になるわけだけど、C のレベルに下りれば解決できるのであれば必要なのは C の知識だし、言語レベル的に C だけど機械の振る舞いも含めるかもしれないし、もっと上のレベルで足りるのであればそこまでが必須スキルであって、闇雲に下りりゃあいいってもんじゃないのは自明だと思うんだよね。あくまで「お仕事」としてはだけど。

つかまずだ。

まず最初に自分の立ち位置を示そう。

……。BINARY HACKS 開き直してみるか。


最後に。

「学習すべき要素」としていちばん納得したのはこれ。

shiro 『なんか論点がすれちがっちゃている感じがしてきました。私が言いたかったのは「どこまで降りることが必要か」ということよりも、「もちろん必要に応じて降りてゆく先に違いはあるけれど、全てのレイヤは同じではなく、何箇所かに強固な足場があるから、その足場を中心に学んでおくべき」ってことなんです。

odz buffer - どこまで必要か

まさに。まさにその通りだと思う。かっこいい。

/* はてなって個々のコメントに permalink ないんだっけ? */

cf.

  1. CASL って言ってる段階でおっさんなのはバレバレだが。そりゃダンプリストと格闘したりはしたけど、ただ雑誌見ながら打ってただけだし。 

  2. 例えば自社製品とか、あるいは業務提携の関係とか、あるいはブランドを利用したい、など 

  3. ただこの場合、必要なのはマシン語だけではなくてアーキテクチャそのものだし、逆にマシン語が中途半端に分かることよりもそっちの方が大事なことの方が多いんじゃなかろうか? 本当に大事なのはマシン語なのか? 細かく説明するの面倒だからとりあえずマシン語って言っちゃってないか? 

About

例によって個人のなんちゃらです