2015年7月10日金曜日

【スマフォアプリマネタイズ】Unity Ads ミートアップ in 大阪 に参加してきた


7/8に大阪で開催されたUnityAdsの勉強会に参加してきました。

【スマフォアプリマネタイズ】Unity Ads ミートアップ #4 in 大阪

UnityAdsミートアップって集まりは毎月東京でやってるらしいです。
今回はたまたま関西での開催だった模様。

到着〜勉強会開始まで

19:45頃に到着したときには15人ぐらいいたかな?
遅刻だと思って急いで来たけどみんな唐揚げ食べてた。
ちゃんとタイムテーブル見てみると20:30開始、19:30は乾杯だったw
タイムテーブル

数人知り合いがいたのでとりあえずビールで乾杯。
唐揚げとピザを食べながらビール。しかも無料。なんて幸せな・・・

20:30頃、Lサイズのピザ3枚が届いたのと同時に勉強会開始。
始まる頃にはみんなお腹いっぱい

20:30〜 Unity Ads トレンドのご案内

Unityジャパン松井さんの発表。
UnityAdsはこんなものですよ〜とか。
どういうアプリに実装されてますよ〜。みたいな紹介。

導入アプリの数や広告数、フィルレート、eCPMとかふむふむって聞いてた。
ところどころの数字は喋っちゃダメって言ってたから伏せとく。
(どこがダメだったかは酔っ払ってて覚えてない)

導入数に関して言うと今年頭からすでに2倍以上になってるらしい。

あとは代表的な広告の表示方法の紹介とか。

代表的な広告表示方法

UnityAdsは動画広告のみなので表示するタイミングが重要。
ざっくりと4種類紹介された。

アイテムプレゼント型

動画みたらアイテムあげるよ!的なあれ。
見るか見ないかユーザーが選べるしいいよね。最近増えてるのも納得。
コンバージョン、eCPM共に高い。

強制表示型

定期的に強制表示されるやつ。かなりうっとうしい。
5秒でスキップできる場合が多いけどそれでもイライラしちゃう。
コンバージョンは並、eCPMは高い。

コンティニュー型

動画みたらもう一度コンティニューさせてあげるよってやつ。
毎回じゃなくハイスコアに届きそうなときとか、ユーザーが悔しい思いをしたときに出すと効果的らしい。たしかに。広告じゃないけどツムツムとかそうやね。
コンバージョンやや高い、eCPMは高い。

ゲーム開始前表示型

開始前に見ると強くてニューゲームできるよ。みたいな。
今からこのゲームを遊ぶ!ってときに出すから効果は低いらしい。
コンバージョン、eCPM共に低い。

Unityを信じて!

この言葉が印象的だったw
効果の高い広告が出やすいように自動的に最適化されていくから2〜3ヶ月は変にいじらず使ってみて。って言ってた。
いじるってブラックリストやホワイトリストで表示する広告をカスタマイズすることね。

21:15~ Unityのアプリに動画広告を実装するには

続いて鎌田さんの発表。
ソースコード見せながらこんな感じで実装できますって紹介。

実装方法

1.UnityAdsのアセットをインポート

※Unity5.2からはUnityAdsが標準ライブラリに含まれるみたいで、アセットのインポートは不要になるらしい。

2.実装する

コードはこれだけ。
using UnityEngine.Advertisements;
public class UnityAdsTest : MonoBehaviour
{
   void Start()
   {
   if(Advertisement.isSupported && Advertisement.isInitialized)
     {
      Advertisement.Initialize("gameID");
     }
   }

   public void ShowAds()
   {
      if( Advertisement.isReady())
      {
        Advertisement.Show();
      }
   }
}
あら簡単。

このままゴリゴリ書き進めてもいいけど
完了・中断とかのコールバック実装やiOS、Android両対応とか
ちょっと踏み込むとだんだん面倒になってくる。(らしい)

次はそれを解決できるヘルパーの紹介。

もっと楽な実装方法

Unity Ads Helper
UnityAdsの実装を超簡単にしてくれるヘルパー。
使い方は上記リンクをみてね。

iOS,AndroidのgameIDを一緒に設定できたり、
OnFinished,OnSkipped,OnFailedとかのコールバックを簡単に実装できたり。
かなり便利そうに見えた。

実装サンプルプロジェクトの紹介

unity-ads-demo
さっきのヘルパーを作ってる人のデモらしい。


動画をみたらコインをプレゼント〜ってありがちな使い方のサンプル。
一度見るとしばらくは「動画を見る」ボタンが押せないクールダウンタイムの実装もされてるので参考にどうぞ。

動画のスキップについて

アイテムプレゼント型の実装だとスキップできない場合が多いよね。
逆に強制表示型だと5秒でスキップみたいなのが多い。

UnityAdsの管理画面からスキップ可否やスキップ可能までの秒数が設定可能だそうな。

UnityAdsの強み

  • eCPMが高い
  • ゲームに特化してる
  • 実装が楽
こんな感じのことを話してた。

Unity5.2以降はアセットの追加すら不要になるみたいだからかなり楽になるね。

まとめ

実装も楽そうだし使ってみましょー。
ゲーム系アプリであれば導入して損はなさそうです。


あと今後はミートアップってことでお肉食べてしゃべる会を目指すらしいですよ。
お肉食べたくなったらUnityの人に連絡しましょう!


Unity系記事まとめ

2015年7月7日火曜日

新ConoHaのオブジェクトストレージ、ダウンロード用一時URL(Temp URL)を試す。

ブラウザからオブジェクトストレージへ直接ファイルアップロードをしたいんだけどブラウザにアクセストークンを渡したくない。
どうにか方法ないかなって調べてたら下記記事を見つけた。

Qiitaの画像アップロード機能も簡単に実装できる。そう、S3ならね。
まさにやりたいことはこれ。でもS3じゃなくてConoHaオブジェクトストレージでやりたい。

調べた。

ConoHaのドキュメントにはForm POSTに関する記述がなかったけど使えないのかな・・・
とりあえず簡単そうな"Temporary URL"を試してみる。

コンテナを作成しファイルをアップロード


"container"ってコンテナを作り、"hello.txt"をアップロードした。
コンテナには何もメタデータを設定していないので、今のところhello.txtは直接GETできない。

トークンの発行

前回の記事と同様にトークンを発行する。
curl -i -X POST \
-H "Accept: application/json" \
-d '{"auth":{"passwordCredentials":{"username":"APIユーザー名","password":"APIユーザーパスワード"},"tenantId":"テナントID"}}' \
https://identity.tyo1.conoha.io/v2.0/tokens

TempURL用のKeyを登録

curl -i -X POST \
-H "Accept: application/json" \
-H "X-Auth-Token: [取得したトークン]" \
-H 'X-Account-Meta-Temp-URL-Key: [セットしたいキー]' \
https://object-storage.tyo1.conoha.io/v1/nc_df3bdbc45bc04950b558834f5728517a
Temporary URL middlewareに4つのキーが必要、みたいに書いてあるけどここでセットしてるのアカウントに対する鍵の1つ目(X-Account-Meta-Temp-URL-Key)っぽいなぁ。1つでいいのかな。残り3つはなんなんやろ。

TempURLを生成するスクリプトを用意

create-tempurl.py
import hmac
from hashlib import sha1
from time import time
method = 'GET'
duration_in_seconds = 60*60*24
expires = int(time() + duration_in_seconds)
path = '/v1/nc_df3bdbc45bc04950b558834f5728517a/container/hello.txt'
key = '[セットしたキー]'
hmac_body = '%s\n%s\n%s' % (method, expires, path)
sig = hmac.new(key, hmac_body, sha1).hexdigest()
s = 'https://{host}{path}?temp_url_sig={sig}&temp_url_expires={expires}'
url = s.format(host='object-storage.tyo1.conoha.io', path=path, sig=sig, expires=expires)
print '%s' % url
pythonにはhmacってライブラリがあるんですなぁ。rubyにもあるのかな。

スクリプト実行

$ python create-tempurl.py 
https://object-storage.tyo1.conoha.io/v1/nc_df3bdbc45bc04950b558834f5728517a/container/hello.txt?temp_url_sig=9775eacc57b95fe57435c8f5d8b6e404a0957930&temp_url_expires=1436284812
こんな感じでURLが返ってくる。
このURLをブラウザで開くとダウンロードされるので一時URLが有効になってるのが確認できた。めでたしめでたし。

とりあえずhmacによる認証ハッシュを生成する方法はわかったので次はFormPOSTを試してみたい。
ConoHaのAPIドキュメントに"Form POST"っぽいものがないけど使えるんだろうか・・・

今日はここまで。

関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

2015年7月5日日曜日

新ConoHaのオブジェクトストレージにAjaxを使ってアップロードする


前回(新ConoHaのオブジェクトストレージ上のデータをAjaxで取得してみる)の続き。

次はAjaxによるアップロードを試します。

参考サイト

コンテナの準備

アップロード先となるコンテナの準備をする。といっても前回の記事から何も変更なかった。
アップロード先のコンテナ
必要なのはX-Container-Meta-Access-Control-Allow-Originメタデータだけみたい。

サイトの準備

参考サイト4つ目のGitHubのソースを真似てWebページを作った。(http://localhost:3000/ のホストとしてアクセス)
https://github.com/naichilab/cors-swift-example/blob/master/app.js
アップロード処理が書かれてるjsファイル。
URL組み立ててtokenつけてPUTするだけっぽい。

トークンの発行

参考サイト3つ目のConoHaドキュメントを見てみると、トークン発行方法が書かれてる。
ターミナルで下記コマンドを実行してトークンを取得する。
curl -i -X POST \
-H "Accept: application/json" \
-d '{"auth":{"passwordCredentials":{"username":"APIユーザー名","password":"APIユーザーパスワード"},"tenantId":"テナントID"}}' \
https://identity.tyo1.conoha.io/v2.0/tokens
長々としたJSONが返ってくるのでaccess->token->idをメモる。
どうもトークンは一度発行すると24時間有効みたいですね。

アップロード実行

さきほど立ち上げたサイトのフォームに入力していく。

  • StorageURL:ConoHaコントロールパネル->API->Object Storage Serviceエンドポイント
  • StorageToken:さきほどメモしたトークン
  • Container:コンテナ名
こんな感じ

File Selectionのボタンからファイルを選ぶとアップロードが始まる。
アップロード完了


すんなりとアップロードできた。
CyberDuckで確認した。

まとめ

  • ConoHaのAPIユーザーを使ってトークンを発行する。
  • コンテナにX-Auth-Tokenメタデータの設定は不要
あってんのかなこれ・・・


だいぶやりたいことに近づいてきたような気がする。
自分のサーバーでトークンを発行してブラウザに渡す→ブラウザが直接オブジェクトストレージにアップロードって感じでいいのかな。
トークンが24時間有効だしこのままじゃ好きなファイルアップロードできちゃうからもーちょい厳しい認証が必要だよなぁ。
どうしたらいいんかな。

関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

2015年7月4日土曜日

新ConoHaのオブジェクトストレージ上のデータをAjaxで取得してみる


新ConoHaのオブジェクトストレージネタ、まだまだ続きます。
前回の記事(新ConoHaのオブジェクトストレージにWeb公開可能なコンテナを作成する。)ではオブジェクトストレージにアップロードしたファイルにブラウザから直接アクセスできるようになりました。

今回は同じファイルをAjax(XmlHttpRequest)を使って取得してみます。

クロスドメインリクエストの制限

Ajaxで別ドメインのデータを取得しようとすると制限にひっかかります。
参考:Ajax クロスドメインリクエスト 制約
CORSってのを使うと上記制限を回避できるそうなので試してみます。

CORS(Cross-Origin Resource Sharing)

まだよくわかってませんがXHR(XmlHttpRequest)のクロスドメイン制約を回避する方法らしいです。
新ConoHaのオブジェクトストレージはOpenStackSwiftで実現してるらしくCORSの設定が可能みたい。

参考:CORS

この制限を超えてファイルアップロードするのが目標ですがまずはGetだけできることを確認します。

サイトの用意

参考サイトに書かれた通りのHTMLを出力するページを用意しました。(Rails)
XHRサンプルフォーム
このサイト(http://localhost:3000)からオブジェクトストレージ(https://object-storage.tyo1.conoha.io/)のファイルをAjaxで取得するにはクロスドメイン制約を抜ける必要があります。

取得してみる

前回の記事で用意したコンテナ(X-Container-Read = .r:* を設定したもの)はこんな感じ。
コンテナのメタデータ
通信内容を確認したいのでChromeのDeveloperToolを開き、Networkタブを表示しておく。
※"DisableCache"にチェックを入れておいたほうがいいと思う。これで結構悩んだ。
ChromeのDeveloperTool
CyberDuckでhello.txtのURLをコピーし、フォームに入力してSubmit。
取得(失敗)
DeveloperTool上はステータスコード200が帰ってきてるみたいだけど画面上にはstatus:0が出たまま。
参考サイトによると何かがおかしいらしい。
参考サイトより:Assuming the request succeeds you should see the response header and body. If something went wrong the response status will be 0.
というかオブジェクトストレージ側に何も設定してないんだから取れたら逆に怖い。

コンテナにCORS用のメタタグを設定

コンテナに下記メタタグを設定する。
X-Container-Meta-Access-Control-Allow-Origin: http://localhost:3000
ちなみにCyberDuckでメタタグを編集できた。Swiftクライアントいらなかったんじゃ?
CyberDuckでメタタグ編集
再度取得してみる。
再取得(成功)
とれた。
Responseに”Access-Control-Allow-Origin:http://localhost:3000”が含まれるようになり、ファイルの内容も取得できてるのがわかる。

まとめ

オブジェクトストレージのファイルをAjax(XmlHttpRequest)を使って取得するには下記設定が必要だった。
  • コンテナにX-Container-Readメタデータを設定する。
  • コンテナにX-Container-Meta-Access-Control-Allow-Originメタデータを設定する。

X-Auth-Token is 何?

参考サイトを忠実にやってたんだけど結局X-Auth-Tokenは設定しなくても動いた。
X-Auth-Tokenとはなんなんだろうか・・・
今回はX-Container-Readで誰でも閲覧可能になってるからいらなかったんだろうか。
最終的にはAjaxを使ったファイルアップロードまで実装したいのでそこらへん知る必要があるのかもしれない。

だれか詳しい人教えてください。

さて次に試すのはAjaxによるアップロードかな。

関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

2015年7月3日金曜日

新ConoHaのオブジェクトストレージにWeb公開可能なコンテナを作成する。

Swiftコマンドラインクライアントで新ConoHaのオブジェクトストレージに接続する。
これの続き。

SwiftコマンドでConoHaのオブジェクトストレージにアクセスできたのでコンテナの設定をしていく。

やりたいこと

コンテナにアップロードしたファイルを認証なしで取得できるようにしたい。
(画像とかをブラウザから認証なしで見れるようにしたい)

参考

Object Storage API v1 (SUPPORTED)
よくわからんけどX-Container-Readってメタデータに.r:*ってのをセットできればいいんかな?

OpenStack SwiftでStatic Webサイトを作る
ググってたら似たようなことしてる記事みつけた。

真似てみる

$ swift post -r '.r:*' hogehoge
これだけでhogehogeコンテナの作成(すでにあれば更新)できるらしい。

確認

コマンドラインで見る方法よくわからんしCyberDuckで見てみる。
それっぽく入ってる。

適当なファイルあげてみる

$ swift upload hogehoge hello.txt 
hogehogeコンテナにhello.txtをアップロード

入った。

ブラウザで見れるかな
URLどうなるんだろうと思ってCyberDuck触ってたらURLコピーする機能あった。便利。

アクセス!

見れたっぽい。
なるほど。Web公開するだけなら簡単やね。

おまけ

コンテナ作成時にメタデータを指定しないと認証エラーしたしちゃんとできてるっぽいかな。

今日はここまで。

関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

2015年7月2日木曜日

Swiftコマンドラインクライアントで新ConoHaのオブジェクトストレージに接続する。


最近リニューアルした新ConoHa(https://www.conoha.jp/)のオブジェクトストレージを試してます。

公式にはオブジェクトストレージを操作する方法として下記2つが紹介されていました。
・CyberDuck(GUIクライアント)を使う方法
・APIを叩く方法

CyberDuck

GUIクライアントは下記記事の通り接続できました。
新ConoHaのオブジェクトストレージにCyberDuckで接続しようとして401認証エラー
コンテナの作成やファイルのアップロード、ダウンロードは問題なくできるんですがコンテナへの属性追加とか、細かい操作はできないみたい。
やりたいのはそっちなので結局APIを使う方法に切り替えることに。

APIによる操作

APIを操作する方法はCURLを使う方法とSwiftコマンドラインクライアントを使う方法がある(?)っぽいです。(ちゃんと調べてない)
swiftコマンドラインクライアントを使う方が、OpenStackSwiftの操作に適してそうな気がしたのでそっちを先に試してみます。

インストールは下記記事の通り行いました。
ConoHaのオブジェクトストレージを操作するためにOpenStackSwiftのコマンドラインクライアントをインストールする

swiftコマンドラインクライアントによる接続

環境

MacOSX 10.10.3
swift 2.4.0

環境変数ファイルを準備

~/swift_conoha
export OS_AUTH_URL=https://identity.tyo1.conoha.io/v2.0 (認証サーバーのAPIエンドポイント)
export OS_TENANT_NAME=XXXXXXXXXXXX (テナント名)
export OS_USERNAME=XXXXXXXXXXXX (APIユーザー名)
export OS_PASSWORD=XXXXXXXXXXXX (APiユーザーパスワード)

起動確認

$ source ~/swift_conoha 
$ swift stat

Auth versions 2.0 and 3 require python-keystoneclient, install it or use Auth
version 1.0 which requires ST_AUTH, ST_USER, and ST_KEY environment
variables to be set or overridden with -A, -U, or -K.
なんか怒られた。python-keystoneclientが足りない?

python-keystoneclientをインストール

$ sudo pip install python-keystoneclient

再チャレンジ

$ swift stat
                        Account: xx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
                     Containers: 1
                        Objects: 1
                          Bytes: 0
Containers in policy "policy-0": 1
   Objects in policy "policy-0": 1
     Bytes in policy "policy-0": 0
               Meta Quota-Bytes: 107374182400
                    X-Timestamp: 1432076457.10619
                     X-Trans-Id: txa813d66137274a32b79f2-0055954ee7
                   Content-Type: text/plain; charset=utf-8
                  Accept-Ranges: bytes
いけたー

とりあえずここまで。

関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

ConoHaのオブジェクトストレージを操作するためにOpenStackSwiftのコマンドラインクライアントをインストールする

新ConoHaのオブジェクトストレージにも採用されてるらしいOpenStack Swift。
コンテナの属性を触るのにAPI操作が必要そうなのでクライアントをインストールしてみる。
いまいちよくわかってないのでメモしとくけど手順合ってるかは不明。

環境

・OS X Yosemite 10.10.3

参考

OpenStack コマンドラインクライアントのインストール
https://swiftstack.com/docs/integration/python-swiftclient.html

前提ソフトウェアのインストール

Python2.6かそれ以降

OS Xには最初から入ってた。
$ python -V
Python 2.7.6
※けどこのままではswiftクライアントが動かず、Homebrew経由で入れ直した。
$ brew install python
$ python -V
Python 2.7.10

setuptoolsパッケージ

これもOS Xには最初から入ってるらしい。

pipパッケージ

これも書かれてる通りのコマンド実行してみる。
$ sudo easy_install pip
・・・略
Installed /Library/Python/2.7/site-packages/pip-7.1.0-py2.7.egg
Processing dependencies for pip
Finished processing dependencies for pip

これでいいのかな。

クライアントのインストール

いろいろクライアントの種類があるみたいだけどオブジェクトストレージだけ操作できればいいからswiftclientってのをインストール。
$ sudo pip install python-swiftclient
・・・略
Successfully installed futures-3.0.3 python-swiftclient-2.4.0 requests-2.7.0 simplejson-3.7.3 six-1.9.0

動かしてみるもエラーで動かない
$ swift
Traceback (most recent call last):
  File "/usr/local/bin/swift", line 7, in <module>
    from swiftclient.shell import main
  File "/Library/Python/2.7/site-packages/swiftclient/shell.py", line 31, in <module>
    from swiftclient.multithreading import OutputManager
  File "/Library/Python/2.7/site-packages/swiftclient/multithreading.py", line 22, in <module>
    from six.moves.queue import PriorityQueue
ImportError: No module named queue
以下のページを発見。
Installing python-swiftclient on OS X Yosemite
どうもMacに最初から入ってるpythonに問題があるらしい。
上記ページの通り、下記コマンドを実行(一旦インストールしたものを削除する)
$ sudo pip uninstall futures
$ sudo pip uninstall requests
$ sudo pip uninstall simplejson
$ sudo pip uninstall six
$ sudo pip uninstall python-swiftclient
Homebrew経由でpythonをインストール
$ brew install python
再度swiftclientをインストール
$ pip install python-swiftclient
これでうまくいきました。
$ swift --version
swift 2.4.0
めでたしめでたし。
次はConoHaのオブジェクトストレージを操作してみる。

関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

2015年7月1日水曜日

新ConoHaのオブジェクトストレージにCyberDuckで接続しようとして401認証エラー


新しくなったConoHa(https://www.conoha.jp/)のオブジェクトストレージを試そうとしてる。
旧ConoHaでは管理画面からコンテナの作成できたんだけど新ConoHaではできなくなってた。(APIやCyberDuckで操作してねって方針)
とりあえず触ってみるためにCyberDuckを使ってみたら接続できなくてハマったのでメモ。

やったこと

一応ConoHaの接続ガイド(https://www.conoha.jp/guide/guide.php?g=49)があるんだけど旧ConoHa用となっててちょいちょい違う。

最初こんな感じで設定したんだけどどうやっても401認証エラー。
これじゃ繋がりません
どうにもこうにも接続できないのでConoHaの中の人に聞いてみたら即答いただけた。
助かる・・・
ありがとうございます。

新しい設定がこれ。
これなら接続できる
すんなりと認証できた。

さぁ難しいのはここからだ・・・


関連記事

ConoHa関連の記事をまとめました。
ConoHa関連まとめ

2015年5月2日土曜日

【本の感想】SQLアンチパターン【★★★★☆】


だいぶ前にOracleのセミナーに参加したときオススメとして紹介されてた本書。
長いこと後回しにしてたけどやっと購入して読んだ。

リレーショナルデータベースの設計や利用に関する25のアンチパターンについて具体的な例をあげて分かりやすくまとめられてる。
  • 実現したいこと
  • やってしまいがちなアンチパターンの説明
  • 見つけ方
  • 用いてもよい場合
  • 解決策
それぞれの章でこんな感じの内容が続く。

役立つ内容も多く、何より楽しく読めたのがよかった。 データベース設計を何度かしたことがある人なら「あるあるネタ」としても楽しめるんじゃないかな。
詳しい例をあげて説明されてるのでデータベース設計の経験がなくても十分理解できると思う。(正規化ぐらいは知っててほしいから応用情報取れるぐらいの人がいいかも)

データベース設計する/したい人やSQL書くことがある人なら万人にオススメ。


以下自分用メモ。

ジェイウォーク(信号無視)

一つのフィールドにカンマ区切りのリスト(文字列)を格納するやつ。

用いてもいい場合

カンマ区切りのデータが必要で、個別にアクセスする必要が全くない場合。

解決策

交差テーブル(多対多テーブル)を作成する。

感想

自分ではさすがにやったことないけど結構やっちゃう人いるよね•••。

ナイーブツリー(素朴な木)

組織図とかの階層構造を実現するために同じテーブルの別レコードを親として参照すること。
部署 [ 部署ID , 親部署ID , 部署名 ] みたいなテーブル。
思慮が浅く親への参照しかもたない素朴(ナイーブ)な解決策らしい。隣接リストとも言う。

用いてもいい場合

隣接リストがアプリケーションで求められているタスクに適している限りは有効。

解決策

代替ツリーモデルを使用する。
  • 経路列挙
  • 入れ子集合
  • 閉包テーブル

感想

隣接リストの利用はシンプルだし色んな本やサイトに書かれている気がする。
アンチパターンだと思ってなかったけど読んでたら確かにハマるなーって思った。
自分が作ったことあるのは階層構造でも浅いものだったから問題なかったんだと思う。
再帰クエリがサポートされてればそれを使って、なければ閉包テーブルを使うのがよさそう。

IDリクワイアド(とりあえずID)

何でもかんでも主キーにIDつけとけってアレ。
めっちゃやってたわー。自然キーがあってもID列作って代替キーにしてたわー(遠い目

用いてもいい場合

ORMフレームワークの規約に従う場合。自然
自然キーとなる項目があまりにも長すぎる場合。

解決策

わかりやすい名前を付け、自然キー、複合キーを活用する。

感想

自分は複合キーを主キーにすると外部キーとして使うときにキー項目すべてを持って行く必要があって、それが嫌(JOINのONとか長くなるし)だから代替キーとしてIDを付けてた。(もちろんUNIQUEKEYはつけるけど)
それに対してこの本では下記のようにかかれててなるほどなーと思った。
「このような開発者の複合キーへの拒否反応は、数学者が2次元や3次元の座標を使うことを拒否し、物体が1次元に存在するかのようにして計算を行うことに似ています。これによって幾何や三角法をはるかに単純化できることは事実ですが、対象とすべき現実世界の物体を正確に表すことはできません。」

自然キーがある場合は代替キーは無意味だと深く納得したので今後の設計に生きると思う。

キーレスエントリ(外部キー嫌い)

外部キー?何それおいしいの?ってやつ。
参照整合性が鬱陶しくて外部キーつけなかったり、そもそも外部キーなんて知らない人がデータベース設計してたり。(こういう場合はExcelみたいな使い方されてるけど)
結局その整合性はアプリケーション側で保たないといけなくなってどうせ破綻するよねって話。

用いてもいい場合

外部キーをサポートしていないDBMSを使う場合は仕方が無い。

解決策

外部キー制約を宣言する。

感想

オーバーヘッドがーってどこかでみた気がするけどこの本で一蹴されてる。
アプリケーション側でチェックのために余分なSelectしたりする事考えたら当たり前やなぁ。

EAV(エンティティ・アトリビュート・バリュー)

Key-Value型のテーブルを用意し、属性を「行」に格納すること。

用いてもいい場合

正当化する理由は簡単には見つからない。

解決策

サブタイプのモデリングを行う。しっかり考えれば別の解決法はいくつかある。
具体的には下記方法がある。
  • シングルテーブル継承
  • 具象テーブル継承
  • クラステーブル継承
  • 半構造化データ

感想

これは一度やっちゃったことあるので耳が痛い話だった。一生こんな設計はしまい。

ポリモーフィック関連

複数の親テーブルを参照するために二重目的の外部キーを使用すること。
ある列にタイプを持たせ、そのタイプに応じて外部キー列の意味合いを変えるみたいな。
Comments ( comment_id , issue_type , issue_id , ... )とか

この例だとissue_typeによってissue_idが参照するテーブルを切り替える。
複数の無差別な関連を持つのでポリモーフィック関連と呼ばれるらしい。
これをやってしまうと参照整合性(外部キー)制約をつけられない。

用いてもいい場合

なし

解決策

交差テーブルを作成する。共通の親テーブルの作成。

感想

これもやったことあるかな。悩むけど要件は満たせるしやっちゃうのよね。
キーレスエントリのアンチパターンを防ぐためにもちゃんと交差テーブル用意しなきゃダメだね。

マルチカラムアトリビュート(複数列属性)

複数の列を定義する。

Bugs ( bug_id , description , tag1 , tag2 ,tag3 )

個数が制限され、検索しづらくなり、タグの追加・削除が複雑になり、一意性の保証ができなくなり、いいことは全くない。

用いてもいい場合

同じテーブルを参照するが、意味合いが違う場合のみ利用可能。 Bugs ( bug_id , description , 報告作業者ID, 修正作業者ID , 確認作業者ID ) みたいな。

これはそもそも各列の意味が違うから根本的に違うと思うけど・・・

解決策

従属テーブルを作成する。 BugTags ( bug_id , tag )

感想

人の作ったMSAccessとか開いてみるとこうなってること多いよね。Excel風。

メタデータトリブル(メタデータ大増殖)

スケーラビリティを高める目的で、テーブルや列をコピーすること。
2008年バグテーブル、2009年バグテーブル、2010年バグテーブル、、、みたいな。

用いてもいい場合

過去データを最新のデータから分離するようなアーカイブ目的の場合。

解決策

パーティショニングと正規化を行う。
水平パーティショニング(またはシャーディング)はDBMSが対応していれば可能。
垂直パーティショニングはBLOBやText等、サイズが大きい列を別テーブルに逃がしたりすること。

または従属テーブルの導入を行う。

感想

これもやりがち。水平パーティショニングは使えるRDBMSが限られてるし膨大な件数を扱う場合はどうするのがいいんだろうなーって思いながら読んでた。

ラウンディングエラー(丸め誤差)

floatやdouble使うと誤差でるよねって話。

用いてもいい場合

intやnumberより大きな値を扱わなければいけない場合。科学技術計算とか。

解決策

numericデータ型を使用する。

感想

これはデータベースに限った話じゃないね。

サーティワンフレーバー(31のフレーバー)

列に入る値を列定義で限定する。
Check制約やドメイン、ユーザ定義型など。
入れたい値の種類が増えるときかなり大変なことに。入れられる値を簡単には確認できないのも面倒だし。

用いてもいい場合

有効値の変更が不要だと断言できる場合。(左/右、有効/無効、オン/オフ等)

解決策

参照テーブルを用意し、限定する値をデータで指定する。

感想

bool型がないRDBMSだとintフィールドを定義してCheck制約で0,1に限定したりするなぁ。bool以外で値を限定したい場合は参照テーブル用意してるし大丈夫かな。

ファントムファイル(幻のファイル)

画像をはじめとする大容量メディアファイルは物理ファイルとして保存することが必須と思い込む。
(物理ファイルとして保存することがアンチパターンなのではない。色々な方法を検討せずに物理ファイルとして保存すべき!と思い込むことがアンチパターン)

用いてもいい場合

大容量ファイルを外部ファイルとして保存することはいくつも正当な理由がある。
  • データベースの容量を減らせる
  • データベースのバックアップ時間、容量を減らせる
  • 外部ファイルならプレビューや編集が用意

解決策

必要に応じてBLOB型を採用する。
物理ファイルもBLOBも一長一短あるので目的に合わせて選択する。

感想

あまりにも収集する画像が膨大すぎてDBストレージに保存するって選択肢が選べないことがあったなぁ。

インデックスショットガン(闇雲インデックス)

インデックスを使わない。もしくは全フィールドにインデックスを貼ること。
インデックスを使うと遅くなると思っていたり、よくわからないから闇雲に貼ったり。

用いてもいい場合

汎用的なデータベースを設計する場合でどのようなクエリを最適化しなければいけないか不明な場合。(この場合、不要なインデックスを削除する必要が出てくる)

解決策

「MENTOR」の原則に基づいてインデックス管理を行う。
  • Measure(測定)
  • Explain(解析)
  • Nominate(指名)
  • Test(テスト)
  • Optimize(最適化)
  • Rebuild(再構築)

感想

MENTORは聞いたことあったけどちゃんと読んだのは初めてだった。
インデックスの調整が必要になったら参考にしてみよう。

フィア・オブ・ジ・アンノウン(恐怖のunknown)

NULLと一般値の混同。
nullはfalseだろうとか、null+空文字は空文字だろうとか、そういう思い込み。

用いてもいい場合

NULLは適切に扱う。

解決策

NULLを一意な値と認識して扱う。
ISNULLやCOALESCEをうまく使う。
必要ならNOTNULLを正しく定義する。

感想

null怖いって人ごく稀にいるよね。
まぁこれは慣れて覚えるしかない。

アンビギュアスグループ(あいまいなグループ)

一度のgroup byでmax(date)とmax(id)とかを取ってくること。
max(date)となった行とmax(id)となった行は一致するとは限らない。

用いてもいい場合

曖昧な動作が問題にならない場合。

解決策

曖昧でない列を使用する。
  • 関数従属性のある列にのみクエリを実行する。
  • 相関サブクエリを使用する
  • 導出テーブルを使用する
  • JOINを使用する
  • 他の列に対しても集約関数を使用する
  • グループごとにすべての値を連結する

感想

誰もが経験済みなんじゃないかな。
自分は導出テーブルを使うことがほとんど。

ランダムセレクション

ランダムに行を取得したい時、全件ソートをしてしまう。
select * from bugs order by rand() limit 1; みたいな。

用いてもいい場合

データセットが十分に少ない場合。

解決策

特定の順番に依存しない。
  • 1と最大値の間のランダムなキー値を選択する(キー値が欠番な場合がある)
  • 欠番の穴の後にあるキー値を選択する(結果が偏る)
  • すべてのキー値を受け取り、ランダムに1つを選択する(アプリケーション側で処理)
  • オフセットを用いてランダムに行を選択する(Limit,rownum等を利用)
  • ベンダー依存の方法(SQLServerのTABLESAMPLE等)

感想

ランダムな行を返したいってあまり必要になったことないなぁ。
LIMIT使うのが現実的か。

プアマンズ・サーチエンジン(貧者のサーチエンジン)

Like '%hoge%' や正規表現で全文検索を行うこと。
インデックスが活用できずフルスキャンとなる。

用いてもいい場合

めったに使用しないクエリ。

解決策

適切なツールを利用する。
  • ベンダー拡張
  • テキストインデックス
  • RDBSから独立した全文検索エンジンの利用

感想

検索機能とかを実装するためには必要になるんだろうなぁ。
ベンダー拡張が使えるならそれが手軽かなと思った。

スパゲッティクエリ

SQLクエリ数は少ないほうがいいと思い込んでいる。
複雑な問題をワンステップで解決しようとし、
3つのシンプルなクエリより複雑な1つのクエリを書いてしまうこと。

用いてもいい場合

単一のクエリをデータソースにひも付けて表示する場合など。

解決策

分けて書く。
全く同じ結果を求めるなら単純なほうが優れている。

感想

うーんよく見かける。プログラミングと同じ、シンプルに考えよう。

インプリシットカラム(暗黙の列)

タイプ数を減らす目的で*を多用する。

用いてもいい場合

試しにSQLを実行する場合など。

解決策

列名を明示的に指定する。

感想

これは以前から徹底してるので問題なし。

リーダブルパスワード(読み取り可能パスワード)

データベースに読み取り可能な形でパスワードを保存する。
ユーザが入力したパスワードを読み取り可能な形でSQLクエリを作る。

用いてもいい場合

作成するアプリケーションが外部アプリケーションのクライアントとなる場合のみ。

解決策

ソルトをつけてパスワードをハッシュ化する

感想

パスワードそのままDBに突っ込むのは問題外だしハッシュ化したものを保存するけど、ソルトの扱いに毎回悩む。どこにソルトを置いておくのかとか。

SQLインジェクション

動的なSQLを記述し、未検証な入力をコードとして実行する。

用いてもいい場合

なし

解決策

誰も信用しない。
  • 変数のパラメータ化
  • プリペアドステートメント
  • コードレビュー

感想

変数のパラメータ化は当然だけどどこまでやっても怖いよね。

シュードキー・ニートフリーク(擬似キー潔癖症)

擬似キー列(連番とか)の欠番を気にして埋める。

用いてもいい場合

なし

解決策

欠番は埋めない。
ロールバックや行削除によって空いた欠番を埋めてはならない。

感想

当たり前。
値を埋めろという上司を説得する方法まで載ってて面白かった。

シー・ノー・エビル(臭いものに蓋)

戻り値を 確認せず、肝心な部分を見逃す。
connection生成時、SQL実行時等、適切なタイミングでエラーチェックを行えばすぐに問題は解決できる。それらを怠って「なぜか動かない」って騒ぐのがアンチパターン。

用いてもいい場合

エラーに対して何もする必要がない場合。(アプリケーション終了時など)

解決策

エラーや戻り値を適切にチェックし、エラーから優雅に解決する。

感想

ちゃんとやるのは大事だけど例外対応って結構めんどうだよね。

ディプロマティック・イミュニティ(外交特権)

システム開発のベストプラクティス(ソース管理を行い、テストを実行し、ドキュメントを整備するなど)を行うに当たって、SQL(特にDDLなど)を特別扱いして別扱いにすること。DBAが専任で存在する場合などに別扱いされやすい。

用いてもいい場合

その場限りのコードの場合。

解決策

包括的に品質問題に取り組む。
品質保証(Quality Assurance)のために下記を行う。
  • プロジェクト要件の明確な定義・文書化
  • 要件に対する解決策の設計・構築
  • 解決策が要件を満たしていることの確認・テスト

感想

たしかにデータベース管理者ってプログラマからすると特殊な位置に見えるよね。仲良く仕事しましょ。

マジックビーンズ(魔法の豆)

MVCのM(モデル)を単純化する目的で、モデルをアクティブレコードそのものとしてしまう。

用いてもいい場合

プロトタイプ作成時

解決策

モデルがアクティブレコードを「持つ」ようにする。
ドメインモデルの使用。

感想

なんとなーく言いたいことはわかるけどそもそもMVCをちゃんと理解できてないのでよくわからなかった。

砂の城

想定不足。性能問題や障害が起きた時どう対処するかといったポリシーが策定されていない。

用いてもいい場合

コストとの兼ね合いでどこまで行うか検討する。

解決策

どのようなトラブルが起こりうるかを可能な限り想定しておく。
トラブルは「当然起きる日常的なもの」と認識する。

感想

これもデータベースに限った話ではなくシステム運用全般に関わる話やね。



ええ本でした。

2015年4月30日木曜日

【Unity、Mac】エディタをVisual Studio Codeに変更する。

昨夜発表されて話題になってたVisualStudioCode、インストールしてUnityで使えるように設定してみました。
今日はMacでのお話。Windowsの人はVisualStudio使ってるだろうし。

環境

OS X Yosemite 10.10.3
Unity 5.0.0 f4
Visual Studio Code 0.1.0

Visual Studio Codeのインストール

https://code.visualstudio.com/
ここから落としてきて解凍。アプリケーションフォルダに移動するだけ。
簡単に起動した。

Unityでの設定

Unityメニュー->Unity->Preferences

External Tools->External Script Editor->Browse...

Visual Studio Code.appを選択

ソリューションファイルを開く

Unityメニュー->Assets->Sync MonoDevelop Project

これでソリューションファイル(.sln)が作られてVisual Studio Codeで開かれる。
File->Open(もしくはCommand+Option+O) でフォルダを開くダイアログを開き、
Unityのプロジェクトフォルダ(.slnファイルがあるフォルダ)を選択する。
Visual Studio Codeの一番下に pick a project と表示されていると思うのでそれを押す。

ソリューションファイルを選択します。どっちでも良さそう?短い方を選んだ。
変なコンソール立ち上がったけど使いそうにないので閉じとく。
(どうみてもブラウザのデバッグウィンドウだな•••)

肝心のエディタ側はエラー出てる。
Error: Cannot start Omnisharp because Mono version >=3.10.0 is required

エラー対応(monoのインストール)

UnityについてくるMonoが古いからこのエラー出るっぽい。
terminal.app起動して brew install mono
$ brew install mono
==> Downloading https://downloads.sf.net/project/machomebrew/Bottles/mono-3.10.0
######################################################################## 100.0%
==> Pouring mono-3.10.0.yosemite.bottle.tar.gz
==> Caveats
To use the assemblies from other formulae you need to set:
  export MONO_GAC_PREFIX="/usr/local"
==> Summary
🍺  /usr/local/Cellar/mono/3.10.0: 1128 files, 218M

エディタ再起動

もいちどSync MonoDevelop Project でOK
エラーなく起動した〜。

感想

難なくインストールできた。
ちょー軽いしgitも認識してくれるみたいでいい感じ。
変数や関数の参照数を出してくれるのもいいね。インラインで参照元も見れるし。
Atomと同じくCommand+Pでなんでも検索ボックスが出てくるみたい。
(画像はコード整形したかったから検索してみた図)
やりたいことができない場合はとりあえずこれ開いて適当に入力してみるといいかも。

そのうちAtomのようにプラグインパラダイスになるんやろなー。
しばらく使ってみましょい。

20150501追記

今まで痛MonoDevelopを使ってたみなさん。
痛VSCodeにも出来るみたいですよ~。

標準MonoDevelopだと日本語入力ができなくて不便だから痛MonoDevelopにしたはずなのに。
あれ、いなくなると寂しい・・・って方、下記を参考にどうぞ。


2015年4月1日水曜日

ConoHaのVPSにchefを使ってRails環境を構築する。~knife solo 準備編~


最近ConoHaのVPSで遊んでます。
安いしコンソール見やすいしいい感じ。

最終的にはRails環境を作りたいんだけどせっかくなのでChefを使ってやってみる。
ただLinuxもあまり分からないから調べることだらけ。
なんとかchef soloが通るとこまで行ったので一旦メモしておきます。

まだまだ頭の中整理できてないので変なこと書いてたら指摘お願いします。

やりたいこと

・標準テンプレートOSをインストールしたConoHaVPSに対して、
・できるだけ少ない手順で knife solo cook が通るようにする。
まずはここまで。

環境

MacBookAir 2013 Mid
OS X Yosemite 10.10.2
Chef Solo 12.1.1(どうやって入れたか覚えてない)

手順

VPSの作成

OSはテンプレートイメージの CentOS 6.5 を選択。

残りは全部安いやつ。
1〜2分待てば起動する。

ローカル側でSSH接続準備

ConoHaコントロールパネルからSSH Private Keyをダウンロードする。
1234567-1.keyみたいな名前。とりあえずホームディレクトリ(~/)に置く。
ここからローカル側Macのターミナル.appで操作

ローカル側(MacBookAir)
$ cd ~
// ~/.sshフォルダが存在しない場合はフォルダ作成
$ mkdir .ssh
$ chmod 700 .ssh/
$ mv 1234567-1.key .ssh/conoha_private_key
$ cd .ssh/
$ chmod 600 conoha_private_key 
$ vi config 
//configファイルは下記のようにして保存。すでにある場合は追記する。
Host conoha
  HostName [VPSのIP]
  IdentityFile ~/.ssh/conoha_private_key
  User root

//うまく設定できていれば下記コマンドでssh接続ができるはず。
$ ssh conoha
[root@v[xxx-xxx-xxx-xxx]] ~]# logout
Connection to xxx.xxx.xxx.xxx closed.
//成功

どうもConoHaの標準テンプレートを使うとVPS作成時に選んだ秘密鍵でrootへSSH接続できるみたい。 この鍵はVPSをホストしている共有サーバ部分への接続にも使うらしいからあまり共用しない方がいい気がするけどよくわからん。もう少し詳しくなってから考えることにする。

VPS側でChef接続用ユーザーの作成

Chefを実行するためにはSSH接続可能且つパスワードなしでsudo可能なユーザーが必要らしい。ConoHa側に専用の'chef'ユーザーを作成し、rootに設定済みの公開鍵をchefユーザーでも利用可能にする。(rootへのssh接続は後で禁止します)

ローカル側(MacBookAir)
$ ssh conoha

ここからVPSのrootユーザーでの操作

VPS側(rootユーザー)
# adduser chef
# passwd chef
ユーザー chef のパスワードを変更。
新しいパスワード: <パスワードを決めて入力>
新しいパスワードを再入力してください: <パスワードを再入力>
passwd: 全ての認証トークンが正しく更新できました。
# visudo
// 下記1行を追加(パスワードなしでsudoできるようになる)
root    ALL=(ALL)       ALL                          ←この行の下に
chef    ALL=(ALL)       NOPASSWD:ALL     ←この行を追加
// 保存して閉じる(esc -> :wq)

# mkdir /home/chef/.ssh
# cp ~/.ssh/authorized_keys /home/chef/.ssh/
# cd /home/chef/.ssh/
# ls -la
drwxr-xr-x 2 root root 4096  4月  1 00:08 2015 .
drwx------ 3 chef chef 4096  4月  1 00:08 2015 ..
-rw------- 1 root root  445  4月  1 00:08 2015 authorized_keys
# chown chef:chef authorized_keys 
# chown chef:chef .
# chmod 600 authorized_keys 
# chmod 700 .
# ls -la
drwx------ 2 chef chef 4096  4月  1 00:08 2015 .
drwx------ 3 chef chef 4096  4月  1 00:08 2015 ..
-rw------- 1 chef chef  445  4月  1 00:08 2015 authorized_keys
これでVPS側は一旦終わり。logoutで抜ける。

ローカル側(MacBookAir)
$ cd ~/.ssh/
$ vi config
//root接続用になってるところをchefに書き換える
Host conoha
  HostName [VPSのIP]
  IdentityFile ~/.ssh/conoha_private_key
  User root   ←  chefに書き換える

//これでchefユーザーでssh接続できるはず。
$ ssh conoha
[chef@vxxx-xxx-xxx-xxx ~]$ who am i
chef     pts/0        2015-04-01 00:17
[chef@vxxx-xxx-xxx-xxx ~]$ logout
Connection to xxx-xxx-xxx-xxx closed.
//成功
これでchef solo実行準備が整った。

ChefでHello World

Chef-Soloを使ってVPSにHello Worldしてみることまでやってみます。

キッチン(リポジトリ)の作成

knife solo initコマンドを使ってリポジトリ(cookbookを入れていくための箱)を作ります。

ローカル側(MacBookAir)
$ cd ~
$ knife solo init conoha-helloworld
WARNING: No knife configuration file found
Creating kitchen...
Creating knife.rb in kitchen...
Creating cupboards...
Setting up Berkshelf...

こんな感じでファイルが生成されてるはず

Cookbookの作成

knife cookbook createコマンドを使ってクックブック(レシピを入れるための箱)を作ります。

ローカル側(MacBookAir)
$ cd ~/conoha-helloworld/
$ knife cookbook create helloworld -o site-cookbooks/

-oで指定した site-cookbooksフォルダにhelloworldクックブックが生成されました。

レシピの編集

helloworldクックブックの中にあるrecipes/default.rbを修正します。
log "Hello World!!"
これだけ。

VPSにchefをインストール

さて、レシピを作ったので実行準備。knife solo prepareコマンドを使ってvpsにchefをインストールします。

ローカル側(MacBookAir)
$ knife -v
Chef: 12.1.1
$ knife solo prepare conoha
WARNING: No knife configuration file found
Bootstrapping Chef...

//インストールログがずらずらと

Thank you for installing Chef!
Generating node config 'nodes/conoha.json'...
//インストール完了

//vps側で確認してみる。
$ ssh conoha

VPS側(chefユーザー)
[chef@vxxx-xxx-xxx-xxx ~]$ knife -v
Chef: 12.1.1
これでVPSにchefをインストールできました。

VPSにレシピを適用

knife solo prepareを行ったときに、conoha-helloworld/nodes/conoha.jsonが生成されています。
このホストに対してどのcookbookを適用するかを管理するファイル。
すでにhelloworldクックブックは作成済みなのでこれを適用するようにconoha.jsonを書き換えます。
{
  "run_list": [
    "recipe[helloworld]"          ←この1行を追加
  ],
  "automatic": {
    "ipaddress": "conoha"
  }
}
あとはcookするだけ。
knife solo cookコマンドでレシピを適用します。
ローカル側(MacBookAir)
$ cd ~/conoha-helloworld/
$ knife solo cook conoha
Running Chef on conoha...
Checking Chef version...
Installing Berkshelf cookbooks to 'cookbooks'...
Resolving cookbook dependencies...
Uploading the kitchen...
Generating solo config...
Running Chef...
Starting Chef Client, version 12.1.1
Compiling Cookbooks...
Converging 1 resources
Recipe: helloworld::default
  * log[Hello World!!] action write
  

Running handlers:
Running handlers complete
Chef Client finished, 1/1 resources updated in 1.36169233 seconds
Hello World出ましたね!今日はここまで。
ここから先はcookbook作成→レシピ編集→conoha.jsonに追記→knife solo cook conohaの繰り返しです。
Rails環境の構築ができたらまた整理します。
Related Posts Plugin for WordPress, Blogger...