<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>アストロデオブログ</title>
	<atom:link href="http://astrodeo.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://astrodeo.com/blog</link>
	<description>Just another WordPress weblog</description>
	<lastBuildDate>Mon, 08 Feb 2010 10:38:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>劇的ビフォーアフター　～アストロデオオフィス編～</title>
		<link>http://astrodeo.com/blog/archives/415</link>
		<comments>http://astrodeo.com/blog/archives/415#comments</comments>
		<pubDate>Mon, 08 Feb 2010 10:38:40 +0000</pubDate>
		<dc:creator>ゴウ</dc:creator>
				<category><![CDATA[雑記]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=415</guid>
		<description><![CDATA[
ビフォー。

アフター。
すごく広くなったので、関係者の方々は気軽に遊びにきてくださいね。

ウィルキンソンジンジャエール、冷えてます。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://astrodeo.com/blog/wp-content/uploads/2010/02/2010-01-28_3.jpg"><img class="alignnone size-large wp-image-416" title="ビフォー" src="http://astrodeo.com/blog/wp-content/uploads/2010/02/2010-01-28_3-600x398.jpg" alt="" width="600" height="398" /></a></p>
<p>ビフォー。</p>
<p><a href="http://astrodeo.com/blog/wp-content/uploads/2010/02/2010-02-08_3.jpg"><img class="alignnone size-large wp-image-417" title="アフター" src="http://astrodeo.com/blog/wp-content/uploads/2010/02/2010-02-08_3-600x398.jpg" alt="" width="600" height="398" /></a></p>
<p>アフター。</p>
<p>すごく広くなったので、関係者の方々は気軽に遊びにきてくださいね。</p>
<p><a href="http://astrodeo.com/blog/wp-content/uploads/2010/02/DSC_0027.jpg"><img class="alignnone size-large wp-image-418" title="ウィルキンソンジンジャエール" src="http://astrodeo.com/blog/wp-content/uploads/2010/02/DSC_0027-600x398.jpg" alt="" width="600" height="398" /></a></p>
<p>ウィルキンソンジンジャエール、冷えてます。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/415/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQueryで画像の遅延読み込みを可能にするlazyload</title>
		<link>http://astrodeo.com/blog/archives/409</link>
		<comments>http://astrodeo.com/blog/archives/409#comments</comments>
		<pubDate>Mon, 08 Feb 2010 02:36:25 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=409</guid>
		<description><![CDATA[画像の多いページは、どうしても読み込むのに時間がかかってしまう。
そこで、画像の読み込みのタイミングを遅らせてページの表示を早めようという試みを可能にするのが、Lazy Loadというプラグイン。
やっていることは、画像を読み込ませる部分に別の軽い画像を代替的に読み込ませることで負荷を軽減するような感じ……で合ってるのかな。
まずは上記のリンク先からlazyloadをダウンロードしてくる。あとjqueryがないと動かないので、持ってなければダウンロードしておく。


&#60;img src="sample.jpg" /&#62;

&#60;img src="sample2.jpg" /&#62;


まあ、たとえばこんな感じで画像を呼んでいるソースがあったとする。


&#60;script&#62;

$(function(){

    $("img").lazyload({

        placeholder: "dummy.gif",

        event: "click"

    });

});

&#60;/script&#62;


これでimgタグで呼んでいるsample.jpgやsample2.jpgがdummy.gifに置き換わる。event: &#8220;click&#8221;というのは画像をクリックしたらsample.jpgなどを読み込むようにしている。デフォルトはページスクロールで画像を読み込むようになっているらしい。
dummy.gifを1px×1pxのgif画像とかにしておけば一つのページに100個とか200個くらい画像を出しているときなんかはそれなりに読み込みが早くなる……と思う。
]]></description>
			<content:encoded><![CDATA[<p>画像の多いページは、どうしても読み込むのに時間がかかってしまう。</p>
<p>そこで、画像の読み込みのタイミングを遅らせてページの表示を早めようという試みを可能にするのが、<a href="http://www.appelsiini.net/projects/lazyload">Lazy Load</a>というプラグイン。</p>
<p>やっていることは、画像を読み込ませる部分に別の軽い画像を代替的に読み込ませることで負荷を軽減するような感じ……で合ってるのかな。</p>
<p>まずは上記のリンク先からlazyloadをダウンロードしてくる。あとjqueryがないと動かないので、持ってなければダウンロードしておく。</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

&lt;img src="sample.jpg" /&gt;

&lt;img src="sample2.jpg" /&gt;

</textarea>
<p>まあ、たとえばこんな感じで画像を呼んでいるソースがあったとする。</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

&lt;script&gt;

$(function(){

    $("img").lazyload({

        placeholder: "dummy.gif",

        event: "click"

    });

});

&lt;/script&gt;

</textarea>
<p>これでimgタグで呼んでいるsample.jpgやsample2.jpgがdummy.gifに置き換わる。event: &#8220;click&#8221;というのは画像をクリックしたらsample.jpgなどを読み込むようにしている。デフォルトはページスクロールで画像を読み込むようになっているらしい。</p>
<p>dummy.gifを1px×1pxのgif画像とかにしておけば一つのページに100個とか200個くらい画像を出しているときなんかはそれなりに読み込みが早くなる……と思う。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/409/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>スタイリッシュなエロサイト、シコールをリリースしました。</title>
		<link>http://astrodeo.com/blog/archives/342</link>
		<comments>http://astrodeo.com/blog/archives/342#comments</comments>
		<pubDate>Mon, 01 Feb 2010 02:54:57 +0000</pubDate>
		<dc:creator>ゴウ</dc:creator>
				<category><![CDATA[ウェブサービス]]></category>
		<category><![CDATA[サイト発表]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=342</guid>
		<description><![CDATA[久しぶりにアストロデオから、ウェブサービスのリリースです。

で、どういうサイトかというと、タイトルの通り、エロサイトです。なんでエロサイトかというと、俺が使いたかったからです。理由は以上です。身内の間では好評なので個人的には満足しています。が、もうちょっとさくっと作る予定だったんですが、最終的に工数とお金（サーバ代）が結構かかってしまいました。泣きそうです。
でも、技術的にも中々勉強になったと思うので、そういった意味では良かったなと思っています。
シコールの概要
世の中にあるエロ系の動画共有サイトから動画を引っ張ってきて、それらを女優ごと、カテゴリ毎に分りやすくまとめて表示するサイトです。また、クリック数によって女優、動画それぞれのランキングに反映しています。
また、cookieを利用して、ログイン無しでお気に入りの動画をストックしておく事ができます。これ意外と便利です。
アフィリエイトとして、DMMとDUGAを表示させています。無料動画で視聴→気に入った商品を購入　という流れに繋がってくれれば作った甲斐があるなぁと思ってます。（せめて・・・サーバ代だけでも・・・）
エンジョイ！オナニー！
あと、今回のサイトの作り方とかについての記事もあるので、興味のある方は是非どうぞ。
真面目にエロサイトを作ってみた【デザイナー編】はコチラから。
真面目にエロサイトを作ってみた【プログラマ編】はコチラ
]]></description>
			<content:encoded><![CDATA[<p>久しぶりにアストロデオから、ウェブサービスのリリースです。</p>
<p><a href="http://shecool.jp/" target="_blank"><img src="http://astrodeo.com/blog/wp-content/uploads/2010/01/shecool2-300x307.jpg" alt="" title="shecool" width="300" height="307" style="border:1px solid #ccc; padding:3px;" /></a></p>
<p>で、どういうサイトかというと、タイトルの通り、<strong>エロサイト</strong>です。なんでエロサイトかというと、俺が使いたかったからです。理由は以上です。身内の間では好評なので個人的には満足しています。が、もうちょっとさくっと作る予定だったんですが、最終的に工数とお金（サーバ代）が結構かかってしまいました。泣きそうです。</p>
<p>でも、技術的にも中々勉強になったと思うので、そういった意味では良かったなと思っています。</p>
<h3>シコールの概要</h3>
<p>世の中にあるエロ系の動画共有サイトから動画を引っ張ってきて、それらを女優ごと、カテゴリ毎に分りやすくまとめて表示するサイトです。また、クリック数によって女優、動画それぞれのランキングに反映しています。</p>
<p>また、cookieを利用して、ログイン無しでお気に入りの動画をストックしておく事ができます。これ意外と便利です。</p>
<p>アフィリエイトとして、DMMとDUGAを表示させています。無料動画で視聴→気に入った商品を購入　という流れに繋がってくれれば作った甲斐があるなぁと思ってます。（せめて・・・サーバ代だけでも・・・）</p>
<p>エンジョイ！オナニー！</p>
<p>あと、今回のサイトの作り方とかについての記事もあるので、興味のある方は是非どうぞ。</p>
<p><a href="http://astrodeo.com/blog/archives/259">真面目にエロサイトを作ってみた【デザイナー編】はコチラから。</a></p>
<p><a href="http://astrodeo.com/blog/archives/257">真面目にエロサイトを作ってみた【プログラマ編】はコチラ</a></p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/342/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>真面目にエロサイトを作ってみた【デザイナー編】</title>
		<link>http://astrodeo.com/blog/archives/259</link>
		<comments>http://astrodeo.com/blog/archives/259#comments</comments>
		<pubDate>Mon, 01 Feb 2010 02:54:35 +0000</pubDate>
		<dc:creator>ゴウ</dc:creator>
				<category><![CDATA[ウェブサービス]]></category>
		<category><![CDATA[サイト発表]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=259</guid>
		<description><![CDATA[真面目にエロサイトを作ってみた【プログラマ編】はコチラ
シコールはコチラ
始まりは独り寂しい夜の隙間から

世の中にたくさんあるエロ系OKの動画共有サイト。
これらは基本的に無料で見る事ができます。それってすごい事ですよね。画質なんかは流石にアレですが、無料で手軽に見られるってのは素晴らしい。俺が中学生の頃はこんな時代じゃなかった。うらやましいです、今の中学生。
でも色々な動画共有サイトに点在するエロ動画を効率良く探すのって結構大変なんです。俺は基本的に女優ベースで探すんですが、いくつものサイトを訪れて検索→視聴　なんてやってられません。いや、やってたんですけどね。エロは強しです。
で、そういう動画サイトをずらーっとまとめて検索＆表示、ランキング付までできちゃうサイトって無いのかなー、って探してみたんですが、まぁ無いわけですよ。使い勝手の良いものが。
じゃあ、作ってみるか。
という感じで、自分たちの持てる知識を総動員して全力でアダルトサイトを作ってみました。
毎度の事ながら、誰にも受け入れられなかったとしても、俺が満足して毎日使っているから良いのです。
どういうサイトにするか

カッコいいデザイン
使っていて飽きないようなデザイン
円滑なオナニーの支援
ログインしないでもマイリストが使える
人気動画や関連動画のレコメンド
動画に関連した商品を表示させる（高画質が欲しい人、全部見たい人用）
軽い（あんまり画像とかゴチャゴチャ使わない）
アダルトサイトっぽく無いようにする（会社で見てもOK!）
女性にウケるデザイン（俺がモテたい）

まぁ、こんな感じのサイトを目指します。
女優一覧の取得
どれくらいの数のAV女優がいるのかわかりませんが、まずは女優一覧を作らない事には始まりません。
どこかに女優一覧がずらーっとあるサイトは無いかなーと探していた所、DMMが膨大な量の女優データを持っているっぽい。なので、こちらを参考にして女優一覧を作る事に。

AV女優一覧（DMMアダルト） 
もちろん俺はデザイナーなので、これらのデータを取得するのはプログラマー陣に任せました。
その辺の技術的考察はエロサイトを作ってみた【プログラマ編】に書いてあるので興味のある方はどうぞ。
ま、とにかくこれで5000人以上のAV女優の名前が取得できました。
女優ごとに商品を関連づけ
DMMのアフィリエイトを利用して、女優ごとに関連した商品を表示させます。詳しい関連付けの方法は【プログラマ編】を参照してもらうとして、この仕組の意図としては、
無料動画を見る
↓
シコーる
↓
続きが見たい！ or 高画質で見たい！
↓
こちらの商品はいかがですか
↓
購入
↓
報酬発生！
↓
サーバ代、生ビール代へ。
という感じです。
動画の取得
メインコンテンツである、エロ動画。
これを取得する先は、いつもお世話になっている以下のサイト！これらのサイトがなければこのサービスは成り立ちません。感謝！

アゲサゲ
MEGAVIDEO
YourFileHost
デイリーモーション
AdultSatellites
veoh
FC2動画
Metacafe

まずはデザインしてみる
デザイン自体は2009年10月くらいから始めました。2009年は自分的に重厚な感じのウェブデザインにハマっておりまして、その流れでさくっと作ってみました。

黒をベースにして、いやらしくならない程度のアクセントとしてピンク、ブルーを配置。
なかなか良いデザインのサイトになったので、これをプログラマ陣に渡して動くようにしてもらいます。 そして一ヶ月くらい後に一通り動くものが出来上がってきました。
これを11月、12月と使ってみたのですが、問題が浮上します。
俺が目指すデザインはこれじゃない
1ヵ月半ほど使ってみて、色々と問題点が見えてきました。

重厚なデザインの為、表示が遅い
読み込みの際に、白背景が見えてから、黒背景が見える（チラつく）
黒でエロサイトってやっぱりちょっと下品
毎日使うサイトとしてはしつこいデザイン（こってりラーメンは毎日食べられない）
会社でみている時に、エロサイトってばれちゃう（モテない）

こんなんじゃダメだ、と思い立ち、リリースを目前にしてデザインの全面リニューアルを行うことに。プログラマは渋い顔。
「大丈夫、CSSだけの修正だから！HTMLはほとんど変わらないから！」
と、なんとか説得して了承を得る事に。
そして新しいデザインへと生まれ変わるのでした。
なんということでしょう・・・

あんなにも黒かった背景が、清潔感ある白に。背景を白にした事による読み込み時の遅延もなくなりました。また、夜のネオン街を彷彿とさせたピンク色を、高原に広がる青空のようなスカイブルーにする事によって、 重ねて清潔感を演出しています。また、匠は随所にAJAX処理を施し、ページ遷移なしでの動画の検索を可能に。
しかし
これらのリニューアルによって、やっぱり大幅なHTMLの修正となり、リリース日はずれ込み、今まで作ったテンプレートを破棄する事となったプログラマ陣はやり場の無い怒りをこの私にぶつけてくるのでした。
「リリースもしてねーのに、リニューアルって・・・」
ぼそぼそと聞こえてくる呟きは、聞こえないふりで受け流します。
サーバーの選定
とまぁ、こんな感じで作っていったんですが、問題はサーバをどうするか。
エロサイトは日本国内のレンタルサーバはアウトな所が多いみたいなので、カルフォルニアにデータセンターを持つ、MEGA FACTORYの専用サーバを借りる事に。
こちら、お値段が初期費用6万円弱＋年間費用9万円で15万ほど。
きっと専用サーバとしては格安なんでしょうが、今まで月額480円とかを利用してきた身分の我々としてはかなりの大盤振る舞い。
さらに、データを取得する為に毎日プログラムが動くので、サーバを2台構成にしないと表示が重くなる　とプログラマに言われたので、結局同じサーバを2台借りる事に。
つまりトータルで30万円の出費です。
ソープ換算で10回分くらいでしょうか。いや、行ったこと無いから知らないけど。
なんか、もうこの時点で採算が取れる気がしません。
そして一般公開へ
こうした経緯があり、Shecool [シコール]は一般公開するに至るのでした。
今回のまとめとしては

毎日使うサイトはすっきりしてた方が良い
でも、デザインして使ってみないと良し悪しは分からない
それらを効率良く作るには、長年の経験がモノをいう
エロサイトだってちゃんとデザインすればカッコいい
こういうのを大真面目にやってるとモテない（たぶん）

最後に
アストロデオたまにちょっとエッチなサイトも作ったりしますが、実は普通のウェブ制作会社です。
こんな我々にウェブサイト作って欲しい！　うちと一緒に仕事しようぜ！　などと思う奇特な方がいらっしゃいましたら、こちらからどしどしご連絡ください。
ちなみに、我々の制作実績の一部は、こちらで公開しています。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://astrodeo.com/blog/archives/257">真面目にエロサイトを作ってみた【プログラマ編】はコチラ</a></p>
<p><a href="http://shecool.jp/" target="_blank">シコールはコチラ</a></p>
<h3>始まりは独り寂しい夜の隙間から</h3>
<p><img title="エロサイト" src="http://astrodeo.com/blog/wp-content/uploads/2010/01/写真2-300x300.jpg" alt="" width="300" height="300" /></p>
<p>世の中にたくさんあるエロ系OKの動画共有サイト。</p>
<p>これらは基本的に無料で見る事ができます。それってすごい事ですよね。画質なんかは流石にアレですが、無料で手軽に見られるってのは素晴らしい。俺が中学生の頃はこんな時代じゃなかった。うらやましいです、今の中学生。</p>
<p>でも色々な動画共有サイトに点在するエロ動画を効率良く探すのって結構大変なんです。俺は基本的に女優ベースで探すんですが、いくつものサイトを訪れて検索→視聴　なんてやってられません。<strong>いや、やってたんですけどね</strong>。エロは強しです。</p>
<p>で、そういう動画サイトをずらーっとまとめて検索＆表示、ランキング付までできちゃうサイトって無いのかなー、って探してみたんですが、まぁ無いわけですよ。使い勝手の良いものが。</p>
<p><strong>じゃあ、作ってみるか。</strong></p>
<p>という感じで、自分たちの持てる知識を総動員して全力でアダルトサイトを作ってみました。</p>
<p>毎度の事ながら、誰にも受け入れられなかったとしても、俺が満足して毎日使っているから良いのです。</p>
<h3>どういうサイトにするか</h3>
<ul>
<li>カッコいいデザイン</li>
<li>使っていて飽きないようなデザイン</li>
<li>円滑なオナニーの支援</li>
<li>ログインしないでもマイリストが使える</li>
<li>人気動画や関連動画のレコメンド</li>
<li>動画に関連した商品を表示させる（高画質が欲しい人、全部見たい人用）</li>
<li>軽い（あんまり画像とかゴチャゴチャ使わない）</li>
<li>アダルトサイトっぽく無いようにする（会社で見てもOK!）</li>
<li>女性にウケるデザイン（俺がモテたい）</li>
</ul>
<p>まぁ、こんな感じのサイトを目指します。</p>
<h3>女優一覧の取得</h3>
<p>どれくらいの数のAV女優がいるのかわかりませんが、まずは女優一覧を作らない事には始まりません。</p>
<p>どこかに女優一覧がずらーっとあるサイトは無いかなーと探していた所、DMMが膨大な量の女優データを持っているっぽい。なので、こちらを参考にして女優一覧を作る事に。</p>
<p><img title="dmm" src="http://astrodeo.com/blog/wp-content/uploads/2010/01/dmm.jpg" alt="" width="300" height="300" /></p>
<p><a href="http://www.dmm.co.jp/digital/videoa/-/actress/" target="_blank">AV女優一覧（DMMアダルト） </a></p>
<p>もちろん俺はデザイナーなので、これらのデータを取得するのはプログラマー陣に任せました。</p>
<p>その辺の技術的考察は<a href="http://astrodeo.com/blog/archives/257">エロサイトを作ってみた【プログラマ編】</a>に書いてあるので興味のある方はどうぞ。</p>
<p>ま、とにかくこれで5000人以上のAV女優の名前が取得できました。</p>
<h3>女優ごとに商品を関連づけ</h3>
<p>DMMのアフィリエイトを利用して、女優ごとに関連した商品を表示させます。詳しい関連付けの方法は<a href="http://astrodeo.com/blog/archives/257">【プログラマ編】</a>を参照してもらうとして、この仕組の意図としては、</p>
<p>無料動画を見る<br />
↓<br />
シコーる<br />
↓<br />
続きが見たい！ or 高画質で見たい！<br />
↓<br />
こちらの商品はいかがですか<br />
↓<br />
購入<br />
↓<br />
報酬発生！<br />
↓<br />
サーバ代、生ビール代へ。</p>
<p>という感じです。</p>
<h3>動画の取得</h3>
<p>メインコンテンツである、エロ動画。</p>
<p>これを取得する先は、いつもお世話になっている以下のサイト！これらのサイトがなければこのサービスは成り立ちません。感謝！</p>
<ul>
<li><a href="http://asg.to/" target="_blank">アゲサゲ</a></li>
<li><a href="http://www.megavideo.com/" target="_blank">MEGAVIDEO</a></li>
<li><a href="http://www.yourfilehost.com/" target="_blank">YourFileHost</a></li>
<li><a href="http://www.dailymotion.com/jp" target="_blank">デイリーモーション</a></li>
<li><a href="http://www.asa.tv/" target="_blank">AdultSatellites</a></li>
<li><a href="http://www.veoh.com/" target="_blank">veoh</a></li>
<li><a href="http://video.fc2.com/" target="_blank">FC2動画</a></li>
<li><a href="http://www.metacafe.com" target="_blank">Metacafe</a></li>
</ul>
<h3>まずはデザインしてみる</h3>
<p>デザイン自体は2009年10月くらいから始めました。2009年は自分的に重厚な感じのウェブデザインにハマっておりまして、その流れでさくっと作ってみました。</p>
<p><img class="alignnone size-full wp-image-320" title="shecool1" src="http://astrodeo.com/blog/wp-content/uploads/2010/01/shecool1.jpg" alt="" width="300" height="300" /></p>
<p>黒をベースにして、いやらしくならない程度のアクセントとしてピンク、ブルーを配置。</p>
<p>なかなか良いデザインのサイトになったので、これをプログラマ陣に渡して動くようにしてもらいます。 そして一ヶ月くらい後に一通り動くものが出来上がってきました。</p>
<p>これを11月、12月と使ってみたのですが、問題が浮上します。</p>
<h3>俺が目指すデザインはこれじゃない</h3>
<p>1ヵ月半ほど使ってみて、色々と問題点が見えてきました。</p>
<ul>
<li>重厚なデザインの為、表示が遅い</li>
<li>読み込みの際に、白背景が見えてから、黒背景が見える（チラつく）</li>
<li>黒でエロサイトってやっぱりちょっと下品</li>
<li>毎日使うサイトとしてはしつこいデザイン（こってりラーメンは毎日食べられない）</li>
<li>会社でみている時に、エロサイトってばれちゃう（モテない）</li>
</ul>
<p>こんなんじゃダメだ、と思い立ち、リリースを目前にしてデザインの全面リニューアルを行うことに。プログラマは渋い顔。</p>
<p><strong>「大丈夫、CSSだけの修正だから！HTMLはほとんど変わらないから！」</strong></p>
<p>と、なんとか説得して了承を得る事に。</p>
<p>そして新しいデザインへと生まれ変わるのでした。</p>
<h3>なんということでしょう・・・</h3>
<p><img class="alignnone size-full wp-image-322" style="border: 1px solid #ccc;" title="shecool" src="http://astrodeo.com/blog/wp-content/uploads/2010/01/shecool.jpg" alt="" width="300" height="300" /></p>
<p>あんなにも黒かった背景が、清潔感ある白に。背景を白にした事による読み込み時の遅延もなくなりました。また、夜のネオン街を彷彿とさせたピンク色を、高原に広がる青空のようなスカイブルーにする事によって、 重ねて清潔感を演出しています。また、匠は随所にAJAX処理を施し、ページ遷移なしでの動画の検索を可能に。</p>
<p>しかし</p>
<p>これらのリニューアルによって、<strong>やっぱり大幅なHTMLの修正となり</strong>、リリース日はずれ込み、今まで作ったテンプレートを破棄する事となったプログラマ陣はやり場の無い怒りをこの私にぶつけてくるのでした。</p>
<p><strong>「リリースもしてねーのに、リニューアルって・・・」</strong></p>
<p>ぼそぼそと聞こえてくる呟きは、聞こえないふりで受け流します。</p>
<h3>サーバーの選定</h3>
<p>とまぁ、こんな感じで作っていったんですが、問題はサーバをどうするか。</p>
<p>エロサイトは日本国内のレンタルサーバはアウトな所が多いみたいなので、カルフォルニアにデータセンターを持つ、<a href="http://www.megafactory.com/">MEGA FACTORY</a>の専用サーバを借りる事に。</p>
<p>こちら、お値段が初期費用6万円弱＋年間費用9万円で15万ほど。</p>
<p>きっと専用サーバとしては格安なんでしょうが、今まで月額480円とかを利用してきた身分の我々としてはかなりの大盤振る舞い。</p>
<p>さらに、データを取得する為に毎日プログラムが動くので、サーバを2台構成にしないと表示が重くなる　とプログラマに言われたので、結局同じサーバを2台借りる事に。</p>
<p>つまり<strong>トータルで30万円の出費</strong>です。</p>
<p>ソープ換算で10回分くらいでしょうか。いや、行ったこと無いから知らないけど。</p>
<p>なんか、もうこの時点で採算が取れる気がしません。</p>
<h3>そして一般公開へ</h3>
<p>こうした経緯があり、Shecool [シコール]は一般公開するに至るのでした。</p>
<p>今回のまとめとしては</p>
<ul>
<li>毎日使うサイトはすっきりしてた方が良い</li>
<li>でも、デザインして使ってみないと良し悪しは分からない</li>
<li>それらを効率良く作るには、長年の経験がモノをいう</li>
<li>エロサイトだってちゃんとデザインすればカッコいい</li>
<li>こういうのを大真面目にやってるとモテない（たぶん）</li>
</ul>
<h3>最後に</h3>
<p>アストロデオたまにちょっとエッチなサイトも作ったりしますが、実は普通のウェブ制作会社です。</p>
<p>こんな我々にウェブサイト作って欲しい！　うちと一緒に仕事しようぜ！　などと思う奇特な方がいらっしゃいましたら、<a href="http://astrodeo.com/contact.php">こちらからどしどしご連絡</a>ください。</p>
<p>ちなみに、我々の制作実績の一部は、<a href="http://astrodeo.com/works.html">こちらで公開しています</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/259/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>真面目にエロサイトを作ってみた【プログラマ編】</title>
		<link>http://astrodeo.com/blog/archives/257</link>
		<comments>http://astrodeo.com/blog/archives/257#comments</comments>
		<pubDate>Mon, 01 Feb 2010 02:54:22 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ウェブサービス]]></category>
		<category><![CDATA[サイト発表]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=257</guid>
		<description><![CDATA[真面目にエロサイトを作ってみた【デザイナー編】はコチラから。
エロサイトを作るにあたって
「スタイリッシュなアダルトサイト思いついたから作るぞ」
（たぶん）そんな感じの一言で始まったSheCoolのサイト制作。見た目がどれくらいスタイリッシュかってのはデザイナーの裁量次第なので、自分の担当はあくまでもシステム部分。発案者の意にできるだけ添えられるように、未熟ながらも自分の技術力を駆使してサイト制作に乗り出しました。
デザインの前に、とりあえず大まかな仕様を決めた時点で、今までやったことのない技術や、そこまで強く意識していなかったことがいくつも出てきました。主なところでは

データのスクレイピング
cronを利用したバッチ処理(DBの自動更新)
SQLのチューニング

辺りが自分にとっての未開領域でした。特にスクレイピングなんて、正直なところそういう単語すら初めて聞くくらいのレベル。所詮は素人プログラマです。ついでに、性欲は人よりあるわりに普段はほとんどアダルト動画を見ないもんですから、どんなアダルト動画の配信サイトがあるのかというのもよく知りませんでした。所詮は素人アダルト動画ウォッチャーです。
しかし今回の制作は何よりもスクレイピングが重要な部分なので、とにかくやってみるしかないってことでやってみました。
開発はCakePHPで行いました。どうしてCakePHPなのかは、今まで開発は基本的にCakePHPを使ってやってきたので一番使い慣れてるっていう、まあそれだけの、水たまりより浅い理由ですよ、ええ。海より深い理由などありゃしません。
データベースはMySQLを使用、ストレージエンジンは全テーブルがMyISAMです。基本的に検索なので、MyISAMが一番早いしトランザクションの必要な処理もないってことなで、MyISAMにしてます。それから後でもまた述べますが、表示側の動的な部分については基本的にjQueryを用いています。
必要なデータのスクレイピング
何をおいてもまずはデータを取得することが必要。データがないと何も始まらない。ナニも始められない。まあ、俺ならデータがなくても妄想だけで始められｍ
最初はfile_get_contents関数を使ってページの情報を持って来て、必要な部分を正規表現で抜き取っていましたが、これが案外しんどい。意外と思い通りの形にデータを取れなかったりする。
そんなときに出会ったのがhtmlSQLというライブラリ。SQLを発行する感覚でスクレイピングが行える。しかもデータがHTMLタグ単位で返って来るので、欲しいところだけを抜き取りやすい。こいつは素晴らしい。中にはどうしてもhtmlSQLでは取れないデータがあったりもしたのですが、たいていのデータはhtmlSQLでいける。使い勝手が良いことは間違いないでしょう。
この解釈が正しいかはちょっと分かりませんが、タグの階層が深くなると、htmlSQLでは取れない場合があるような気がする。divタグの中にdivタグがあって、さらにその中にdivが…って感じでどんどん深くなると、divタグの中身を取って来ようと思った時に、一番深いところのdivの情報が上手く取れないようなケースがあるっぽい。でも取れてる場合もあるから、確かなことは言えないです。
女優データの取得
デザイナー編でもあったように、女優のデータは全てDMMから取得しています。DMMには女優の一覧ページと各女優の詳細情報のページがあるので、まず女優一覧のページから各女優の詳細情報ページへのURLを取得し、それぞれのURLにリクエストを投げて、情報を取得する。名前を複数持っている女優に関しては、名前を分割してDBにデータを入力しています。
一旦全女優のデータを取得した後は、新人の女優さんだけを定期的に見に行くようにして、その女優のデータがDBに入っていなければINSERT処理を行うようにしました。
それにしても、最近の女優さんはみんな可愛いですね。
DMMの商品データの取得
サーバー代、生ビール代をゲットするために必要なデータだから、ここはしっかり取得しなければならない。いえ、しっかり取得しなければならないのは他のデータも同じですけどね。
DMMは、各女優さんとその女優さんが出演しているDVDや動画がすでに関連づいているので、女優のデータを取得するときに一緒に商品データも取得するようにしています。女優ごとの商品の一覧ページへリクエストを投げて、その一覧ページから必要な情報を取得する。商品情報が複数ページにわたっている場合は、もちろんその全てのページのデータを取得する。
DMMではこの商品情報が人気順や価格順で見られるようになっているので、shecoolでもそこは連動させるようにしました。DMMを見ていると人気順はちょくちょく変化しているようなので、定期的に商品情報のページを見に行って、DBの方も更新するようにしています。人気順用のカラムを作っておいて、その中身を更新する感じ。毎回全商品の順位が変動するわけではないので、順位の変動があった商品だけを更新するようにしています。でないと、サーバーに無駄な負荷をかけてしまうからね。
DMMの方に追加された新しい商品情報の取得も、この人気順を入れ替える処理と同時に行っています。商品の一覧ページに載っている商品の情報がすでにDBに入っているかどうかを検証し、DBにデータがあった場合は、順位が変動していたら順位を入れ替えるUPDATE処理を行い、変動していなかったら何もしない、そしてDBにデータがなかった場合はINSERT処理を行うような分岐処理をしています。
動画データの取得
考え方としては、取得先のサイトの検索ボックスにキーワードを入力して、見つかった動画の詳細な情報を取得する感じ。スクレイピングの場合は直接検索ボックスにキーワードを入力するわけではないけど、フォームから送信されるデータは、特にそれが検索フォームのような場合は、多くがGETメソッドによってURLの後ろにパラメータを追加するように作られているので、最初からパラメータのついたURLに接続すれば情報を取得できる。
今回は、DBに入っている女優の名前とタグをそれぞれパラメータとしてURLに追加し、見つかった動画を取得しました。例えば『麻美ゆま』というパラメータをURLに追加して見つかった動画を取得するということは、検索ボックスに『麻美ゆま』というワードを入力して見つかった動画の情報を取得することに等しいことになります。
当然ながらサイトによってデータの取得の仕方が多少変わってきますが、htmlSQLが存分に活躍してくれたおかげで、何とかなりました。
データを取得させていただいた諸サイトさんには、この場を借りてお礼を申し上げます。
スクレイピングにおける注意点
スクレイピングは相手のサイトからデータを取ってくる作業なわけで、だからリクエストをたくさん投げ続ければそれだけサーバーにかかる負荷が大きくなります。自分側のサーバーはともかく、相手側のサーバーには極力迷惑をかけないようにしたいですね。連続してリクエストを投げすぎないようにする、取得する情報は必要最小限に抑える、余計なリクエストを投げない、その辺を意識しながらコーディングする必要があるかと思います。
DBへのデータ入力
データを取得したら当然次は入力です……が、しかし今回は入力する情報量が非常に多く、スクレイピングで必要な情報を取得する度にINSERT処理を行うと、1000件ほどのデータを入力するのに丸一日掛かってしまうようなこともありました。最初は数万件の動画情報を取得してDBに入れなければならなかったため、1000件の動画情報を入力するのに一日掛かっていたら時間がいくらあっても足りません。一日が40時間になってもきっと足りない。
更には、情報の取得だけならともかく、shecoolはタグや女優が動画やDMMの商品とHABTMで関連付けているため（関連付けに関しては後述）、アソシエーションを設定してCakePHPのsaveallメソッドでまとめて入力処理を行うと、一件辺りの動画情報の入力時間がもっと長くなる可能性も出てきます。というか、実際に長くなってました。
少しでも処理時間を短縮するためには、余計なインスタンスを生成しないようにするなど、考えられる点は多々あると思うのですが、今回は大幅な時間の短縮が求められたため、そんな焼け石にぬるま湯をかける程度の改善ではどうにもなりませんでした。かけるなら最低でも液体窒素くらいでないといけない。
そこで今回は、バッチ処理時にsaveメソッドやsaveallメソッドでのINSERT処理は行わずに、スクレイピングで必要な情報を持ってきたら、その情報を入力するINSERT文をテキストファイルに書き出す処理を行い、シェルから直接SQLを実行するようにしました。関連付けも、動画とタグ、動画同士、それぞれにINSERT用のテキストファイルを作成し、同様の処理を行いました。


shell_exec("mysql --user=ユーザー名 --password=パスワード DB名 &#60; ".ファイルパス);


コードはこんな感じ。
CakePHP 1.2にはシェル機能があり、それを利用すればバッチ処理をサーバー側で実行できるみたいです。サーバーでcronの設定を行い、毎日決まった時間に自動で処理を実行するようにしておけば、DBへのアクセスが比較的少ないと思われる時間帯（早朝とか）などに処理を走らせることができる。この辺りの設定とかに関しては、先輩プログラマのお力を借りました。というかほとんどやってもらいました。
おかげで、入力処理の時間は大幅に短縮されました。液体ヘリウムをかけたかのようでした（？）
動画との関連付け
shecoolでは、動画、タグ、女優がそれぞれ動画とHABTMで関連付いています（動画と動画は正確にはHABTMではないですが、多対多で結び付いているという意味で）。また、DMMの商品データとタグもHABTMで関連付いています。DMMの商品と女優は一対多。
動画と動画
動画同士は、タイトルがどれだけ類似しているかで関連付けを行っています。similar_text関数を使い、一定以上のパーセンテージ（今回は70%に設定している）が返って来たら関連していると判断し、バッチで処理を行うINSERT文をテキストファイルに書き出す。
処理自体はループ処理なので、ソースとしてはそんなに複雑にはなりません。ただ、10000件の動画があったら10000件の動画それぞれが他の9999件の動画と関連するのかどうかをチェックしなければならないため、処理自体はかなり重いです。動画の件数が増えれば増えるほど、処理はどんどん重くなる。なので、うっかりループの中で全動画データをSELECTするような処理を書くとメモリが大変なことになってしまうので、こういう時は、処理を行う前に一度全動画のデータを適当なメンバ変数などに持たせておくようにした方が良いと思います。処理時間を短くするには、とにかく必要以上にクエリは投げない。これが大事のようです。
本来なら、新規に動画データをDBに入力した時に同時に関連付けも行えば良いのですが、前述のデータ入力の項目にもあるように、それらを同時に行うのは負荷が大きいので、関連付けは関連付けで別個にINSERT処理を行っています。一度関連付けを行った動画データにもう一度同じ処理を行わせるのは無意味なので、今回は動画のテーブルに関連付けを行っていないかどうかの判定フラグ用のカラムを用意し、関連付けの処理を行うのはそのフラグが立っているデータのみ、つまりまだ関連付けが行われていない動画だけを抽出して処理を行うようにしました。
ただ、similar_text関数の検証という記事でも書いたように、マルチバイト文字の比較に関しては、そこまでの正確性はないように思えます。一つの動画を複数に分割してあるような動画（サンプル動画１、サンプル動画２、みたいな）を関連付けるのが一番の目的であり、それについては問題なく関連付いているので目的は達成できていますが、それ以外にも、およそ関連しているとは思えないような動画同士が関連している可能性は多分にあります。youtubeとかに比べると、関連付けのレベルは全然劣りますね。
動画とタグ
動画とタグの関連付けは、DBに入っているタグ名をループで回し、動画のタイトルとディスクリプションの中にそのタグ名が入っているかどうかを判定し、入っていればその動画とタグを関連付けています。
それ以外に、スクレイピングのところで述べたように、動画は、タグ名をURLのパラメータに追加して、該当する動画が見つかったらそれらの情報を取得しています。だから例えば『女教師』というタグ名で動画を検索して引っかかった動画に関しては、タイトルやディスクリプションに『女教師』という単語がなくても、『女教師』のタグとは関連付けるようにしてあります。
動画と女優
動画と女優は、処理自体は動画とタグの関連付けと同様です。動画のタイトルやディスクリプションに女優名があるかどうかを判定し、あればその動画と女優を結び付ける。さらには女優名をURLのパラメータに追加して、例えば『麻美ゆま』という女優名で引っかかった動画に関しては、タイトルやディスクリプションの内容に関係なく、『麻美ゆま』とは関連付けています。
最初は、動画に女優のIDを持たせて、一対多で結び付けていました。つまり『麻美ゆま』で検索して見つかった動画に関しては、その動画の中に他の女優が出ていても、関連する女優は麻美ゆま一人だけでした。ですが話し合いの結果、複数の女優が出演している動画にはそれら全ての女優を関連付けた方が良いだろうという結論に達し、急遽HABTMに切り替えました。
ただし関連付けの判定方法がタイトルやディスクリプションの中に女優名が入っているかどうかだけなので、タイトルにもディスクリプションにも名前のない女優は、動画の中に出てきたとしても関連付いてはいないです。
DMM商品とタグ
DMMの商品の詳細情報が載っているページには、その商品に関連するジャンルの情報が載っています。そのジャンルとこちらのDBに入っているタグ名を比較し、一致するものがあった場合にはそのタグを関連付けるようにしています。
一つの商品に対し関連付いているジャンルは複数ある場合がほとんどですが、今回はそれら一つ一つをループさせてタグ名と一致するかどうか比較するような処理は行わずに、複数あるジャンルを一つの文字列として連結させ、正規表現を使ってタグ名がその文字列の中に存在するかどうかを判定して関連付けを行うようにしました。クエリが減るからこっちの方が処理時間は速いです。
DMM商品と女優
特別な処理は何もしてないです。商品データの取得でも述べたように、商品は基本的に誰かしらの女優と結び付いているので、その女優さんのIDを商品テーブルに持たせているだけです。
サーバーの選定・設定
日本のサーバーは、アダルトコンテンツを許可していないところが多いみたいですね。なので今回はMEGAFACTORYという海外のサーバーを利用しました。
サーバーの複数台の利用
当初は一台のサーバーで運用を考えていました。しかしクライアント（弊社社長）の度重なる要求に応えているうちにどんどんと仕様が膨らみ、それに伴って裏側の処理（動画の取得など）の負荷がかなり大きくなってしまったため、一台では運用が厳しくなってしまいました。
そこで、サーバーを二台に分割することにしました。複数台の運用、そして二つのDBを連動させるという試みは自分にとっては初めてだったため、何をどう設定すれば良いのかさっぱりでしたが、づや先輩やとりよし先輩のお力を最大限に借りることで、無事に乗り切りました。借りたっていうか、任せたの方が正しい表現ですけど。
要は、スレーブとマスターの二つにサーバーを分け、スレーブの方はSELECT処理のみ接続し、INSERTやUPDATE、DELETE処理を行う時には、マスターの方に接続するように設定している……らしいです。裏側の処理はずっとマスターの方に接続していれば問題ないですが、表示側はその時々に応じて接続先を切り替えなければなりません。shecoolでは動画や女優にランキングをつけているため、表示側でもINSERTやUPDATEの処理が行われることはあります。そういう時だけ、接続先をマスターの方に切り替えるわけです。
これはsaveメソッドやupdateメソッドをオーバーライドすることで切り替えを実現しています。一時的にマスターに接続して処理を行い、終わったら接続先をスレーブに戻す、そんな処理を書いています。
Sennaの導入
SQLにおいて、LIKE検索は速度が遅い。だから特定の文字列を検索したい時にはLIKE検索よりも全文検索を利用するのが常套だと思うのですが、しかしMySQLの全文検索はマルチバイトに対応していない。FULLTEXTのインデックスを張るだけでは残念ながら日本語の全文検索は上手くできないみたいです。
対応策はいくつかあるようですが、今回はSennaという組み込み型の全文検索エンジンを利用して、日本語での全文検索を可能にしました。
SennaをMySQLに組み込むにはMySQLをコンパイルし直す必要があるらしく、そこがちょっと大変で、結構苦戦するみたいです。しかしここでも当然のように先輩方のお力を借りた私は、特に苦労はしていないです。使えない後輩を持つと先輩は大変なんだってのがこれでよく分かりますね。気をつけましょう。
表示側の動き
サイトの性質上、shecoolは画像や動画のデータが多いです。デザイナー編にある、どういうサイトにするかのところで、画像をあまりごちゃごちゃ使わないようにしたいとか何とか言っちゃおりますが、できるだけ使わないようにしたって、一度に結構な数の画像が表示されます。まあ、そういうサイトなんだから仕方ないわけなんですが、加えて、関連動画の表示や検索ワードに該当する動画データと関連するDMM商品の表示など、複雑なSQLクエリを発行する箇所が多々あり、ページ全体はかなり重いです。全体の読み込みが終わるまでにかなりの時間を要してしまう。
そういうわけで、少しでも速くするために、さまざまな試みが要求されました。Sennaの導入もその一つですね。
jQueryの利用
shecoolでは、表示の動的な変化にjQueryを多用しています。細かい動きがあるたびにページ全体を読み込んでいたら目的の動画にたどりつくまでに日がくれてしまいますからね。気持ちが萎えることこの上ないですね。萎えるのは気持ちだけではないと思います。
jQueryでなければならない理由は特にありませんが、Ajaxでスライドなどのアニメーション効果をつけたいと思った時に、個人的にはjQueryを利用するのが手軽に実現できて良いと思っています。HTTP通信でのページ読み込みも簡単に行えるし、自分はprototypeよりはjQueryを使うことが多いです。
クエリの最適化
本気で最適化をするとなったら、これから書くこと以外にもかなりいろいろとやらないといけませんが、とりあえずは明日のためのその１。技術レベルが素人以上素人未満の僕みたいな奴でもすぐに手を出せるような項目を、いくつか挙げてみます。

SELECT文を発行する際、取得するカラムは常に必要なものだけにする。ワイルドカード（*）は使わない方が良い。
COUNTの場合も、ワイルドカードは使わずにカラムに主キーなどを指定することで、実行速度は上がる。


SELECT COUNT(*) FROM `movies`
⇒SELECT COUNT(`id`) FROM `movies`


WHERE句にORを使うようなときはINに置き換えた方が良い。


SELECT `title` FROM `movies` WHERE `id` = 1 OR `id` = 2
⇒SELECT `title` FROM `movies` WHERE `id` IN(1,2)


インデックスをちゃんと張る。
DBのテーブルを見直して、ちゃんとインデックスが張られているかチェックしましょう。主キーだけでなく、特にWHERE句に関わってくるようなカラムは、インデックスを張っておいた方がSELECT文の場合には実行速度が速くなります。
あとはCake側でアソシエーションの設定をしている場合は、必要なところ以外はunbindModelをしておくことも時間短縮の一つですね。joinしていると遅くなったりするから。
何にせよ、まずはどのクエリがボトルネックになっているかを洗い出すことが肝心です。基本的にはEXPLAINで地味にこつこつと見るのが良い。クエリを解析すればどのクエリが遅いのかは分かるので、そこに改善を施すわけです。今回は全文検索のインデックスがjoinの時にうまく効かなくて、構成から変えたところもあったりしました。
先輩プログラマ曰く、だいぶ頑張って実行時間を短縮したけどまだまだ遅い感じがする、だそうです。
キャッシュを使う
ページにキャッシュを利かせれば、表示は当然速くなります。でも当サイトではユーザーの動きがダイレクトに出るところがあるから（最近見た動画とか）、ページキャッシュを作ってもすぐに消される羽目になり、それではキャッシュを利かせるメリットがない。
ということで、今回はクエリの方にキャッシュを利かせました。検索のように、毎回同じクエリが投げられるとは限らないようなところはともかく、人気の動画や人気の女優を取得してくるようなところは常に同じクエリが投げられるので、クエリ自体をキャッシュ化しても特に問題はないわけです。ページ読み込みの際に、すでにクエリのキャッシュが存在している場合にはそちらを見に行くようにすれば、これまた時間短縮につながります。
Ajaxで画像を読み込むようにする
画像が多いと、どうしても全体が読み込み終わるまでにある程度の時間を要してしまいますね。そこで、画像の読み込みは後回しにしてしまっても良いような部分は、ページの読み込みが完了してからAjaxで読み込ませるようにする方法もあります。前述の通り、shecoolはjQueryを多用しているので、例えばフッター部など、スクロールしないと見えないような部分はonLoadでAjax通信を行って画像を読み込ませるというのも、有効な手段だと思います。読み込みが終わるまではloading用のgif画像でも出しておけば良いんじゃないでしょうか。
そして公開へ
こんな感じで、ことあるごとに追加される機能や、その都度発生するバグ、そしてデザインの修正、果てはリリースしてないのに大幅にリニューアルするという、これはもはやパワハラなんじゃねーのってくらいの仕様変更に耐えながら地道なチューニングを行い、ようやくリリースまでこぎつけたわけです。
分からないことだらけで大変ではありましたが、とても有意義な制作でした。特に、今までそんなに重いページを作ったことがなかったせいか、クエリの最適化とかは全然意識したことがなかったんですけど、これは今後も必ず役に立ってくるところだと思うので、とても勉強になりました。
それに何といっても、動作テストと称して毎日仕事中に堂々とアダルト動画をひたすら見続けることができたのでとても有意義な制作でした。お気に入りの動画を探してマイリストに登録するところなんて、テストに見せかけてかなり真剣に選抜してました。とても有意義な制作でした。
ただ、大真面目にアダルト動画をチェックしてマイリストを作っている自分とか、取得するサイトの中でもどのサイトが優良な動画をたくさん持っているかを入念に吟味している自分とかを客観的に見たら、「ああ、こいつは絶対にモテないな。右手しか恋人候補がいねえ」って思いました。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://astrodeo.com/blog/archives/259">真面目にエロサイトを作ってみた【デザイナー編】</a>はコチラから。</p>
<h3>エロサイトを作るにあたって</h3>
<p><strong>「スタイリッシュなアダルトサイト思いついたから作るぞ」</strong></p>
<p>（たぶん）そんな感じの一言で始まった<a href="http://shecool.jp/">SheCool</a>のサイト制作。見た目がどれくらいスタイリッシュかってのはデザイナーの裁量次第なので、自分の担当はあくまでもシステム部分。発案者の意にできるだけ添えられるように、未熟ながらも自分の技術力を駆使してサイト制作に乗り出しました。</p>
<p>デザインの前に、とりあえず大まかな仕様を決めた時点で、今までやったことのない技術や、そこまで強く意識していなかったことがいくつも出てきました。主なところでは</p>
<ul>
<li>データのスクレイピング</li>
<li>cronを利用したバッチ処理(DBの自動更新)</li>
<li>SQLのチューニング</li>
</ul>
<p>辺りが自分にとっての未開領域でした。特にスクレイピングなんて、正直なところそういう単語すら初めて聞くくらいのレベル。所詮は素人プログラマです。ついでに、性欲は人よりあるわりに普段はほとんどアダルト動画を見ないもんですから、どんなアダルト動画の配信サイトがあるのかというのもよく知りませんでした。所詮は素人アダルト動画ウォッチャーです。</p>
<p>しかし今回の制作は何よりもスクレイピングが重要な部分なので、とにかくやってみるしかないってことでやってみました。</p>
<p>開発はCakePHPで行いました。どうしてCakePHPなのかは、今まで開発は基本的にCakePHPを使ってやってきたので一番使い慣れてるっていう、まあそれだけの、水たまりより浅い理由ですよ、ええ。海より深い理由などありゃしません。</p>
<p>データベースはMySQLを使用、ストレージエンジンは全テーブルがMyISAMです。基本的に検索なので、MyISAMが一番早いしトランザクションの必要な処理もないってことなで、MyISAMにしてます。それから後でもまた述べますが、表示側の動的な部分については基本的にjQueryを用いています。</p>
<h3>必要なデータのスクレイピング</h3>
<p>何をおいてもまずはデータを取得することが必要。データがないと何も始まらない。ナニも始められない。まあ、俺ならデータがなくても妄想だけで始められｍ</p>
<p>最初は<a href="http://php.net/manual/ja/function.file-get-contents.php" target="_blank">file_get_contents関数</a>を使ってページの情報を持って来て、必要な部分を正規表現で抜き取っていましたが、これが案外しんどい。意外と思い通りの形にデータを取れなかったりする。</p>
<p>そんなときに出会ったのが<a href="http://www.jonasjohn.de/lab/htmlsql.htm" target="_blank">htmlSQL</a>というライブラリ。SQLを発行する感覚でスクレイピングが行える。しかもデータがHTMLタグ単位で返って来るので、欲しいところだけを抜き取りやすい。こいつは素晴らしい。中にはどうしてもhtmlSQLでは取れないデータがあったりもしたのですが、たいていのデータはhtmlSQLでいける。使い勝手が良いことは間違いないでしょう。</p>
<p>この解釈が正しいかはちょっと分かりませんが、タグの階層が深くなると、htmlSQLでは取れない場合があるような気がする。divタグの中にdivタグがあって、さらにその中にdivが…って感じでどんどん深くなると、divタグの中身を取って来ようと思った時に、一番深いところのdivの情報が上手く取れないようなケースがあるっぽい。でも取れてる場合もあるから、確かなことは言えないです。</p>
<h4>女優データの取得</h4>
<p><a href="http://astrodeo.com/blog/archives/259">デザイナー編</a>でもあったように、女優のデータは全てDMMから取得しています。DMMには女優の一覧ページと各女優の詳細情報のページがあるので、まず女優一覧のページから各女優の詳細情報ページへのURLを取得し、それぞれのURLにリクエストを投げて、情報を取得する。名前を複数持っている女優に関しては、名前を分割してDBにデータを入力しています。</p>
<p>一旦全女優のデータを取得した後は、新人の女優さんだけを定期的に見に行くようにして、その女優のデータがDBに入っていなければINSERT処理を行うようにしました。</p>
<p>それにしても、最近の女優さんはみんな可愛いですね。</p>
<h4>DMMの商品データの取得</h4>
<p>サーバー代、生ビール代をゲットするために必要なデータだから、ここはしっかり取得しなければならない。いえ、しっかり取得しなければならないのは他のデータも同じですけどね。</p>
<p>DMMは、各女優さんとその女優さんが出演しているDVDや動画がすでに関連づいているので、女優のデータを取得するときに一緒に商品データも取得するようにしています。女優ごとの商品の一覧ページへリクエストを投げて、その一覧ページから必要な情報を取得する。商品情報が複数ページにわたっている場合は、もちろんその全てのページのデータを取得する。</p>
<p>DMMではこの商品情報が人気順や価格順で見られるようになっているので、shecoolでもそこは連動させるようにしました。DMMを見ていると人気順はちょくちょく変化しているようなので、定期的に商品情報のページを見に行って、DBの方も更新するようにしています。人気順用のカラムを作っておいて、その中身を更新する感じ。毎回全商品の順位が変動するわけではないので、順位の変動があった商品だけを更新するようにしています。でないと、サーバーに無駄な負荷をかけてしまうからね。</p>
<p>DMMの方に追加された新しい商品情報の取得も、この人気順を入れ替える処理と同時に行っています。商品の一覧ページに載っている商品の情報がすでにDBに入っているかどうかを検証し、DBにデータがあった場合は、順位が変動していたら順位を入れ替えるUPDATE処理を行い、変動していなかったら何もしない、そしてDBにデータがなかった場合はINSERT処理を行うような分岐処理をしています。</p>
<h4>動画データの取得</h4>
<p>考え方としては、取得先のサイトの検索ボックスにキーワードを入力して、見つかった動画の詳細な情報を取得する感じ。スクレイピングの場合は直接検索ボックスにキーワードを入力するわけではないけど、フォームから送信されるデータは、特にそれが検索フォームのような場合は、多くがGETメソッドによってURLの後ろにパラメータを追加するように作られているので、最初からパラメータのついたURLに接続すれば情報を取得できる。</p>
<p>今回は、DBに入っている女優の名前とタグをそれぞれパラメータとしてURLに追加し、見つかった動画を取得しました。例えば『麻美ゆま』というパラメータをURLに追加して見つかった動画を取得するということは、検索ボックスに『麻美ゆま』というワードを入力して見つかった動画の情報を取得することに等しいことになります。</p>
<p>当然ながらサイトによってデータの取得の仕方が多少変わってきますが、htmlSQLが存分に活躍してくれたおかげで、何とかなりました。</p>
<p>データを取得させていただいた諸サイトさんには、この場を借りてお礼を申し上げます。</p>
<h4>スクレイピングにおける注意点</h4>
<p>スクレイピングは相手のサイトからデータを取ってくる作業なわけで、だからリクエストをたくさん投げ続ければそれだけサーバーにかかる負荷が大きくなります。自分側のサーバーはともかく、相手側のサーバーには極力迷惑をかけないようにしたいですね。連続してリクエストを投げすぎないようにする、取得する情報は必要最小限に抑える、余計なリクエストを投げない、その辺を意識しながらコーディングする必要があるかと思います。</p>
<h3>DBへのデータ入力</h3>
<p>データを取得したら当然次は入力です……が、しかし今回は入力する情報量が非常に多く、スクレイピングで必要な情報を取得する度にINSERT処理を行うと、1000件ほどのデータを入力するのに丸一日掛かってしまうようなこともありました。最初は数万件の動画情報を取得してDBに入れなければならなかったため、1000件の動画情報を入力するのに一日掛かっていたら時間がいくらあっても足りません。一日が40時間になってもきっと足りない。</p>
<p>更には、情報の取得だけならともかく、shecoolはタグや女優が動画やDMMの商品とHABTMで関連付けているため（関連付けに関しては後述）、アソシエーションを設定してCakePHPのsaveallメソッドでまとめて入力処理を行うと、一件辺りの動画情報の入力時間がもっと長くなる可能性も出てきます。というか、実際に長くなってました。</p>
<p>少しでも処理時間を短縮するためには、余計なインスタンスを生成しないようにするなど、考えられる点は多々あると思うのですが、今回は大幅な時間の短縮が求められたため、そんな焼け石にぬるま湯をかける程度の改善ではどうにもなりませんでした。かけるなら最低でも液体窒素くらいでないといけない。</p>
<p>そこで今回は、バッチ処理時にsaveメソッドやsaveallメソッドでのINSERT処理は行わずに、スクレイピングで必要な情報を持ってきたら、その情報を入力するINSERT文をテキストファイルに書き出す処理を行い、シェルから直接SQLを実行するようにしました。関連付けも、動画とタグ、動画同士、それぞれにINSERT用のテキストファイルを作成し、同様の処理を行いました。</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

shell_exec("mysql --user=ユーザー名 --password=パスワード DB名 &lt; ".ファイルパス);

</textarea>
<p>コードはこんな感じ。</p>
<p>CakePHP 1.2にはシェル機能があり、それを利用すればバッチ処理をサーバー側で実行できるみたいです。サーバーでcronの設定を行い、毎日決まった時間に自動で処理を実行するようにしておけば、DBへのアクセスが比較的少ないと思われる時間帯（早朝とか）などに処理を走らせることができる。この辺りの設定とかに関しては、先輩プログラマのお力を借りました。というかほとんどやってもらいました。</p>
<p>おかげで、入力処理の時間は大幅に短縮されました。液体ヘリウムをかけたかのようでした（？）</p>
<h3>動画との関連付け</h3>
<p>shecoolでは、動画、タグ、女優がそれぞれ動画とHABTMで関連付いています（動画と動画は正確にはHABTMではないですが、多対多で結び付いているという意味で）。また、DMMの商品データとタグもHABTMで関連付いています。DMMの商品と女優は一対多。</p>
<h4>動画と動画</h4>
<p>動画同士は、タイトルがどれだけ類似しているかで関連付けを行っています。<a href="http://jp.php.net/manual/ja/function.similar-text.php" target="_blank">similar_text関数</a>を使い、一定以上のパーセンテージ（今回は70%に設定している）が返って来たら関連していると判断し、バッチで処理を行うINSERT文をテキストファイルに書き出す。</p>
<p>処理自体はループ処理なので、ソースとしてはそんなに複雑にはなりません。ただ、10000件の動画があったら10000件の動画それぞれが他の9999件の動画と関連するのかどうかをチェックしなければならないため、処理自体はかなり重いです。動画の件数が増えれば増えるほど、処理はどんどん重くなる。なので、うっかりループの中で全動画データをSELECTするような処理を書くとメモリが大変なことになってしまうので、こういう時は、処理を行う前に一度全動画のデータを適当なメンバ変数などに持たせておくようにした方が良いと思います。処理時間を短くするには、とにかく必要以上にクエリは投げない。これが大事のようです。</p>
<p>本来なら、新規に動画データをDBに入力した時に同時に関連付けも行えば良いのですが、前述のデータ入力の項目にもあるように、それらを同時に行うのは負荷が大きいので、関連付けは関連付けで別個にINSERT処理を行っています。一度関連付けを行った動画データにもう一度同じ処理を行わせるのは無意味なので、今回は動画のテーブルに関連付けを行っていないかどうかの判定フラグ用のカラムを用意し、関連付けの処理を行うのはそのフラグが立っているデータのみ、つまりまだ関連付けが行われていない動画だけを抽出して処理を行うようにしました。</p>
<p>ただ、<a href="http://astrodeo.com/blog/archives/258">similar_text関数の検証</a>という記事でも書いたように、マルチバイト文字の比較に関しては、そこまでの正確性はないように思えます。一つの動画を複数に分割してあるような動画（サンプル動画１、サンプル動画２、みたいな）を関連付けるのが一番の目的であり、それについては問題なく関連付いているので目的は達成できていますが、それ以外にも、およそ関連しているとは思えないような動画同士が関連している可能性は多分にあります。youtubeとかに比べると、関連付けのレベルは全然劣りますね。</p>
<h4>動画とタグ</h4>
<p>動画とタグの関連付けは、DBに入っているタグ名をループで回し、動画のタイトルとディスクリプションの中にそのタグ名が入っているかどうかを判定し、入っていればその動画とタグを関連付けています。</p>
<p>それ以外に、スクレイピングのところで述べたように、動画は、タグ名をURLのパラメータに追加して、該当する動画が見つかったらそれらの情報を取得しています。だから例えば『女教師』というタグ名で動画を検索して引っかかった動画に関しては、タイトルやディスクリプションに『女教師』という単語がなくても、『女教師』のタグとは関連付けるようにしてあります。</p>
<h4>動画と女優</h4>
<p>動画と女優は、処理自体は動画とタグの関連付けと同様です。動画のタイトルやディスクリプションに女優名があるかどうかを判定し、あればその動画と女優を結び付ける。さらには女優名をURLのパラメータに追加して、例えば『麻美ゆま』という女優名で引っかかった動画に関しては、タイトルやディスクリプションの内容に関係なく、『麻美ゆま』とは関連付けています。</p>
<p>最初は、動画に女優のIDを持たせて、一対多で結び付けていました。つまり『麻美ゆま』で検索して見つかった動画に関しては、その動画の中に他の女優が出ていても、関連する女優は麻美ゆま一人だけでした。ですが話し合いの結果、複数の女優が出演している動画にはそれら全ての女優を関連付けた方が良いだろうという結論に達し、急遽HABTMに切り替えました。</p>
<p>ただし関連付けの判定方法がタイトルやディスクリプションの中に女優名が入っているかどうかだけなので、タイトルにもディスクリプションにも名前のない女優は、動画の中に出てきたとしても関連付いてはいないです。</p>
<h4>DMM商品とタグ</h4>
<p>DMMの商品の詳細情報が載っているページには、その商品に関連するジャンルの情報が載っています。そのジャンルとこちらのDBに入っているタグ名を比較し、一致するものがあった場合にはそのタグを関連付けるようにしています。</p>
<p>一つの商品に対し関連付いているジャンルは複数ある場合がほとんどですが、今回はそれら一つ一つをループさせてタグ名と一致するかどうか比較するような処理は行わずに、複数あるジャンルを一つの文字列として連結させ、正規表現を使ってタグ名がその文字列の中に存在するかどうかを判定して関連付けを行うようにしました。クエリが減るからこっちの方が処理時間は速いです。</p>
<h4>DMM商品と女優</h4>
<p>特別な処理は何もしてないです。商品データの取得でも述べたように、商品は基本的に誰かしらの女優と結び付いているので、その女優さんのIDを商品テーブルに持たせているだけです。</p>
<h3>サーバーの選定・設定</h3>
<p>日本のサーバーは、アダルトコンテンツを許可していないところが多いみたいですね。なので今回は<a href="http://www.megafactory.com/" target="_blank">MEGAFACTORY</a>という海外のサーバーを利用しました。</p>
<h4>サーバーの複数台の利用</h4>
<p>当初は一台のサーバーで運用を考えていました。しかしクライアント（弊社社長）の度重なる要求に応えているうちにどんどんと仕様が膨らみ、それに伴って裏側の処理（動画の取得など）の負荷がかなり大きくなってしまったため、一台では運用が厳しくなってしまいました。</p>
<p>そこで、サーバーを二台に分割することにしました。複数台の運用、そして二つのDBを連動させるという試みは自分にとっては初めてだったため、何をどう設定すれば良いのかさっぱりでしたが、づや先輩やとりよし先輩のお力を最大限に借りることで、無事に乗り切りました。借りたっていうか、任せたの方が正しい表現ですけど。</p>
<p>要は、スレーブとマスターの二つにサーバーを分け、スレーブの方はSELECT処理のみ接続し、INSERTやUPDATE、DELETE処理を行う時には、マスターの方に接続するように設定している……らしいです。裏側の処理はずっとマスターの方に接続していれば問題ないですが、表示側はその時々に応じて接続先を切り替えなければなりません。shecoolでは動画や女優にランキングをつけているため、表示側でもINSERTやUPDATEの処理が行われることはあります。そういう時だけ、接続先をマスターの方に切り替えるわけです。</p>
<p>これはsaveメソッドやupdateメソッドをオーバーライドすることで切り替えを実現しています。一時的にマスターに接続して処理を行い、終わったら接続先をスレーブに戻す、そんな処理を書いています。</p>
<h4>Sennaの導入</h4>
<p>SQLにおいて、LIKE検索は速度が遅い。だから特定の文字列を検索したい時にはLIKE検索よりも全文検索を利用するのが常套だと思うのですが、しかしMySQLの全文検索はマルチバイトに対応していない。FULLTEXTのインデックスを張るだけでは残念ながら日本語の全文検索は上手くできないみたいです。</p>
<p>対応策はいくつかあるようですが、今回は<a href="http://qwik.jp/senna/FrontPageJ.html" target="_blank">Senna</a>という組み込み型の全文検索エンジンを利用して、日本語での全文検索を可能にしました。</p>
<p>SennaをMySQLに組み込むにはMySQLをコンパイルし直す必要があるらしく、そこがちょっと大変で、結構苦戦するみたいです。しかしここでも当然のように先輩方のお力を借りた私は、特に苦労はしていないです。使えない後輩を持つと先輩は大変なんだってのがこれでよく分かりますね。気をつけましょう。</p>
<h3>表示側の動き</h3>
<p>サイトの性質上、shecoolは画像や動画のデータが多いです。デザイナー編にある、どういうサイトにするかのところで、画像をあまりごちゃごちゃ使わないようにしたいとか何とか言っちゃおりますが、できるだけ使わないようにしたって、一度に結構な数の画像が表示されます。まあ、そういうサイトなんだから仕方ないわけなんですが、加えて、関連動画の表示や検索ワードに該当する動画データと関連するDMM商品の表示など、複雑なSQLクエリを発行する箇所が多々あり、ページ全体はかなり重いです。全体の読み込みが終わるまでにかなりの時間を要してしまう。</p>
<p>そういうわけで、少しでも速くするために、さまざまな試みが要求されました。Sennaの導入もその一つですね。</p>
<h4>jQueryの利用</h4>
<p>shecoolでは、表示の動的な変化にjQueryを多用しています。細かい動きがあるたびにページ全体を読み込んでいたら目的の動画にたどりつくまでに日がくれてしまいますからね。気持ちが萎えることこの上ないですね。萎えるのは気持ちだけではないと思います。</p>
<p>jQueryでなければならない理由は特にありませんが、Ajaxでスライドなどのアニメーション効果をつけたいと思った時に、個人的にはjQueryを利用するのが手軽に実現できて良いと思っています。HTTP通信でのページ読み込みも簡単に行えるし、自分はprototypeよりはjQueryを使うことが多いです。</p>
<h4>クエリの最適化</h4>
<p>本気で最適化をするとなったら、これから書くこと以外にもかなりいろいろとやらないといけませんが、とりあえずは明日のためのその１。技術レベルが素人以上素人未満の僕みたいな奴でもすぐに手を出せるような項目を、いくつか挙げてみます。</p>
<ul>
<li>SELECT文を発行する際、取得するカラムは常に必要なものだけにする。ワイルドカード（*）は使わない方が良い。</li>
<li>COUNTの場合も、ワイルドカードは使わずにカラムに主キーなどを指定することで、実行速度は上がる。</li>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

SELECT COUNT(*) FROM `movies`
⇒SELECT COUNT(`id`) FROM `movies`

</textarea>
<li>WHERE句にORを使うようなときはINに置き換えた方が良い。</li>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

SELECT `title` FROM `movies` WHERE `id` = 1 OR `id` = 2
⇒SELECT `title` FROM `movies` WHERE `id` IN(1,2)

</textarea>
<li>インデックスをちゃんと張る。</li>
<p>DBのテーブルを見直して、ちゃんとインデックスが張られているかチェックしましょう。主キーだけでなく、特にWHERE句に関わってくるようなカラムは、インデックスを張っておいた方がSELECT文の場合には実行速度が速くなります。</ul>
<p>あとはCake側でアソシエーションの設定をしている場合は、必要なところ以外はunbindModelをしておくことも時間短縮の一つですね。joinしていると遅くなったりするから。</p>
<p>何にせよ、まずはどのクエリがボトルネックになっているかを洗い出すことが肝心です。基本的にはEXPLAINで地味にこつこつと見るのが良い。クエリを解析すればどのクエリが遅いのかは分かるので、そこに改善を施すわけです。今回は全文検索のインデックスがjoinの時にうまく効かなくて、構成から変えたところもあったりしました。</p>
<p>先輩プログラマ曰く、だいぶ頑張って実行時間を短縮したけどまだまだ遅い感じがする、だそうです。</p>
<h4>キャッシュを使う</h4>
<p>ページにキャッシュを利かせれば、表示は当然速くなります。でも当サイトではユーザーの動きがダイレクトに出るところがあるから（最近見た動画とか）、ページキャッシュを作ってもすぐに消される羽目になり、それではキャッシュを利かせるメリットがない。</p>
<p>ということで、今回はクエリの方にキャッシュを利かせました。検索のように、毎回同じクエリが投げられるとは限らないようなところはともかく、人気の動画や人気の女優を取得してくるようなところは常に同じクエリが投げられるので、クエリ自体をキャッシュ化しても特に問題はないわけです。ページ読み込みの際に、すでにクエリのキャッシュが存在している場合にはそちらを見に行くようにすれば、これまた時間短縮につながります。</p>
<h4>Ajaxで画像を読み込むようにする</h4>
<p>画像が多いと、どうしても全体が読み込み終わるまでにある程度の時間を要してしまいますね。そこで、画像の読み込みは後回しにしてしまっても良いような部分は、ページの読み込みが完了してからAjaxで読み込ませるようにする方法もあります。前述の通り、shecoolはjQueryを多用しているので、例えばフッター部など、スクロールしないと見えないような部分はonLoadでAjax通信を行って画像を読み込ませるというのも、有効な手段だと思います。読み込みが終わるまではloading用のgif画像でも出しておけば良いんじゃないでしょうか。</p>
<h3>そして公開へ</h3>
<p>こんな感じで、ことあるごとに追加される機能や、その都度発生するバグ、そしてデザインの修正、<strong>果てはリリースしてないのに大幅にリニューアルする</strong>という、これはもはやパワハラなんじゃねーのってくらいの仕様変更に耐えながら地道なチューニングを行い、ようやくリリースまでこぎつけたわけです。</p>
<p>分からないことだらけで大変ではありましたが、とても有意義な制作でした。特に、今までそんなに重いページを作ったことがなかったせいか、クエリの最適化とかは全然意識したことがなかったんですけど、これは今後も必ず役に立ってくるところだと思うので、とても勉強になりました。</p>
<p>それに何といっても、動作テストと称して<strong>毎日仕事中に堂々とアダルト動画をひたすら見続けること</strong>ができたのでとても有意義な制作でした。お気に入りの動画を探してマイリストに登録するところなんて、テストに見せかけてかなり真剣に選抜してました。とても有意義な制作でした。</p>
<p>ただ、大真面目にアダルト動画をチェックしてマイリストを作っている自分とか、取得するサイトの中でもどのサイトが優良な動画をたくさん持っているかを入念に吟味している自分とかを客観的に見たら、「<strong>ああ、こいつは絶対にモテないな。右手しか恋人候補がいねえ</strong>」って思いました。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/257/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>自分のプログラマとしての値段を考えてみる</title>
		<link>http://astrodeo.com/blog/archives/401</link>
		<comments>http://astrodeo.com/blog/archives/401#comments</comments>
		<pubDate>Sun, 31 Jan 2010 09:36:20 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[雑記]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=401</guid>
		<description><![CDATA[イーワーカーというサイトのコストの達人というコーナーに工数計算の一例が載っていた。
このサイト、近々閉鎖してしまうようなので、そのうちこのリンクも意味はなくなってしまうのですが、せっかくなので紹介させてもらいませう。
工数計算の中に、開発スタッフの単価の例が載っていて、それがちょっと興味深かった。
スタッフ単価の決め方は会社単位で結構違うようで、これが通例だというのはどうもなさそうなのですが、主なところではスタッフの実績や年収から単価を求めるのが一般的のような感じの雰囲気っぽいです。
上記のコーナーには年収から単価を求める具体例も載ってました。
例えば、年収が450万の人の場合。会社側から見て、この人にはまずこの金額の給与を1年間に支払うわけですが、それとは別に、福利厚生だの何だのという費用の負担も会社はしなければならない。その費用の負担と年収を合わせたものを雇用コストと呼ぶそうですが、この雇用コストの計算はおおよそ年収の1.5倍くらいを見ると良いようです。だから450万の年収がある人の年間の雇用コストは　450　×　1.5　=　675万円　になりますね。
単純に考えて、この人は年間に675万円以上の売り上げを立てないと、会社にとっては赤字です。だからといって675万円ぴったりでも微妙。それじゃ会社の利益がないですからね。会社がどれだけの利益を期待するのかはそれこそ会社単位で違うでしょうが、ここでは30%の利益率を期待していることにしましょうか。
いや、決してアストロデオがそうなんだよってことじゃなくてね。っていうか、ぶっちゃけうちの社長がどれだけの利益率を期待してるか、正確な数値は知らないです。まあ、たぶんあの人のことだから、具体的に何%みたいなことは特に考えてないような気もしますけど。多けりゃ何でも良い、みたいな。
さて、年間雇用コストが675万かかる人が30%の利益を上乗せするとなると、まあめんどいので計算は省きますが、964万円くらいになります。これがこのスタッフの年間収支になるわけです。
1か月の勤務日数はだいたいのところが20日としているはずなので、1年でおよそ240日。これを元に1日の単価を出すと　964　÷　240　≒　4万円　になります。したがって、この人の単価は4万円ということになりますね。
あくまでもこれは一例なので、450万の人なら絶対に1日あたり4万で動かなければいけないというわけではありませんが、こういう目安があると自分の単価も出しやすいかと思います。
しかし、年収450万ですか……今の僕にとっては、結構高いラインですよ、その年収。
]]></description>
			<content:encoded><![CDATA[<p>イーワーカーというサイトのコストの達人というコーナーに<a href="http://www.eworker.jp/contents/article/article.php?t=1&amp;c=19">工数計算の一例</a>が載っていた。</p>
<p>このサイト、近々閉鎖してしまうようなので、そのうちこのリンクも意味はなくなってしまうのですが、せっかくなので紹介させてもらいませう。</p>
<p>工数計算の中に、開発スタッフの単価の例が載っていて、それがちょっと興味深かった。</p>
<p>スタッフ単価の決め方は会社単位で結構違うようで、これが通例だというのはどうもなさそうなのですが、主なところではスタッフの実績や年収から単価を求めるのが一般的のような感じの雰囲気っぽいです。</p>
<p>上記のコーナーには年収から単価を求める具体例も載ってました。</p>
<p>例えば、年収が450万の人の場合。会社側から見て、この人にはまずこの金額の給与を1年間に支払うわけですが、それとは別に、福利厚生だの何だのという費用の負担も会社はしなければならない。その費用の負担と年収を合わせたものを雇用コストと呼ぶそうですが、この雇用コストの計算はおおよそ年収の1.5倍くらいを見ると良いようです。だから450万の年収がある人の年間の雇用コストは　450　×　1.5　=　675万円　になりますね。</p>
<p>単純に考えて、この人は年間に675万円以上の売り上げを立てないと、会社にとっては赤字です。だからといって675万円ぴったりでも微妙。それじゃ会社の利益がないですからね。会社がどれだけの利益を期待するのかはそれこそ会社単位で違うでしょうが、ここでは30%の利益率を期待していることにしましょうか。</p>
<p>いや、決してアストロデオがそうなんだよってことじゃなくてね。っていうか、ぶっちゃけうちの社長がどれだけの利益率を期待してるか、正確な数値は知らないです。まあ、たぶんあの人のことだから、具体的に何%みたいなことは特に考えてないような気もしますけど。多けりゃ何でも良い、みたいな。</p>
<p>さて、年間雇用コストが675万かかる人が30%の利益を上乗せするとなると、まあめんどいので計算は省きますが、964万円くらいになります。これがこのスタッフの年間収支になるわけです。</p>
<p>1か月の勤務日数はだいたいのところが20日としているはずなので、1年でおよそ240日。これを元に1日の単価を出すと　964　÷　240　≒　4万円　になります。したがって、この人の単価は4万円ということになりますね。</p>
<p>あくまでもこれは一例なので、450万の人なら絶対に1日あたり4万で動かなければいけないというわけではありませんが、こういう目安があると自分の単価も出しやすいかと思います。</p>
<p>しかし、年収450万ですか……今の僕にとっては、結構高いラインですよ、その年収。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/401/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>開発の工数について</title>
		<link>http://astrodeo.com/blog/archives/379</link>
		<comments>http://astrodeo.com/blog/archives/379#comments</comments>
		<pubDate>Thu, 28 Jan 2010 10:10:02 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[雑記]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=379</guid>
		<description><![CDATA[ちょっと興味深い記事を見つけた。
開発を行う際には、どれくらいの工数がかかるのか、その規模感をイメージすることはとても大事なことだ。工数が出せれば、費用の概算も出しやすい。
しかし、これがなかなか難しい。というより、今までの自分はあまりそういうのを意識したことがない。とりあえず仕事が来たら手を動かして終わりって感じだったので、見積もりを算出したりとかは全くと言っていいほど無関心だったのだけれど、これからはそういうことを考える必要も出てくると思う。
上の記事には、人月あたりの総工数を出す計算式が載っている。これが絶対的な基準ということはないだろうけど、一応の目安として知っておくのはありかもしれない。
総工数（人月） ＝ 0.97 × 画面数 ＋ 0.26 × バッチ数
よく分かんないけど、何かいろいろとサンプルを取ってみたらこんな感じの式に辿り着いたらしい。
それから、開発の規模を測る方法として、昔はステップ数から規模を割り出していたようだけど、今ではFP法という、ソースの長さではなくファンクションの中身（どれだけ複雑な処理を行っているかとかかな、たぶん）で規模感を掴む方法がよく用いられてるっぽい。このFPを割り出す計算式も上の記事の中に載っていた。
FP ＝ 23.6 × 画面数 ＋ 3.1 × バッチ数
経験則から自分である程度正確に工数を出せるのなら問題ないが、僕みたいに全く見積もりができないような人間にとっては、こういう式を一つの指標として見積もりを出す練習をするのも良いかもしれない。
もっとも僕の場合、バッチの処理数はどこまでを1と数えるのかが、実はよく分かっていなかったりするのだけど……。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://it.impressbm.co.jp/e/2008/12/22/362">ちょっと興味深い記事</a>を見つけた。</p>
<p>開発を行う際には、どれくらいの工数がかかるのか、その規模感をイメージすることはとても大事なことだ。工数が出せれば、費用の概算も出しやすい。</p>
<p>しかし、これがなかなか難しい。というより、今までの自分はあまりそういうのを意識したことがない。とりあえず仕事が来たら手を動かして終わりって感じだったので、見積もりを算出したりとかは全くと言っていいほど無関心だったのだけれど、これからはそういうことを考える必要も出てくると思う。</p>
<p>上の記事には、人月あたりの総工数を出す計算式が載っている。これが絶対的な基準ということはないだろうけど、一応の目安として知っておくのはありかもしれない。</p>
<p><strong>総工数（人月） ＝ 0.97 × 画面数 ＋ 0.26 × バッチ数</strong></p>
<p>よく分かんないけど、何かいろいろとサンプルを取ってみたらこんな感じの式に辿り着いたらしい。</p>
<p>それから、開発の規模を測る方法として、昔はステップ数から規模を割り出していたようだけど、今ではFP法という、ソースの長さではなくファンクションの中身（どれだけ複雑な処理を行っているかとかかな、たぶん）で規模感を掴む方法がよく用いられてるっぽい。このFPを割り出す計算式も上の記事の中に載っていた。</p>
<p><strong>FP ＝ 23.6 × 画面数 ＋ 3.1 × バッチ数</strong></p>
<p>経験則から自分である程度正確に工数を出せるのなら問題ないが、僕みたいに全く見積もりができないような人間にとっては、こういう式を一つの指標として見積もりを出す練習をするのも良いかもしれない。</p>
<p>もっとも僕の場合、バッチの処理数はどこまでを1と数えるのかが、実はよく分かっていなかったりするのだけど……。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/379/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HABTMで相手のテーブルのフィールドを指定する</title>
		<link>http://astrodeo.com/blog/archives/376</link>
		<comments>http://astrodeo.com/blog/archives/376#comments</comments>
		<pubDate>Tue, 26 Jan 2010 00:18:53 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=376</guid>
		<description><![CDATA[二つのテーブルがHABTMで関連づいている場合、関連づいている相手のテーブルのフィールドを指定するには、コンテイナブルというビヘイビアを使うと良いらしい。
ビヘイビアを使用するには、モデルにビヘイビアの指定を追加しても良いし、特定の箇所でしか使わないような場合はコントローラーで追加しても良い。


//modelで追加する場合
class User extends AppModel {

    var $actsAs = array('Containable');

}

//controllerで追加する場合
$this-&#62;User-&#62;Behaviors-&#62;attach('Containable');


例えばUserとTagがHABTMで関連づいているとしたら、以下のような感じでフィールドを指定する。


$params = array('contain' =&#62; array('Tag.id', 'Tag.name'));

$this-&#62;User-&#62;find('all', $params);


]]></description>
			<content:encoded><![CDATA[<p>二つのテーブルがHABTMで関連づいている場合、関連づいている相手のテーブルのフィールドを指定するには、コンテイナブルというビヘイビアを使うと良いらしい。</p>
<p>ビヘイビアを使用するには、モデルにビヘイビアの指定を追加しても良いし、特定の箇所でしか使わないような場合はコントローラーで追加しても良い。</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

//modelで追加する場合
class User extends AppModel {

    var $actsAs = array('Containable');

}

//controllerで追加する場合
$this-&gt;User-&gt;Behaviors-&gt;attach('Containable');

</textarea>
<p>例えばUserとTagがHABTMで関連づいているとしたら、以下のような感じでフィールドを指定する。</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

$params = array('contain' =&gt; array('Tag.id', 'Tag.name'));

$this-&gt;User-&gt;find('all', $params);

</textarea>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/376/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HTMLのbuttonタグ</title>
		<link>http://astrodeo.com/blog/archives/374</link>
		<comments>http://astrodeo.com/blog/archives/374#comments</comments>
		<pubDate>Wed, 20 Jan 2010 06:20:08 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[HTML]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=374</guid>
		<description><![CDATA[HTMLにbuttonタグという、ボタンを表示するタグがある。
このボタン、Firefoxだとsubmitが既定値になっているらしいのだけど、IEとかだとsubmitの属性がついていない状態が既定値になっているっぽい。
なので


&#60;button value="送信"&#62;送信&#60;/button&#62;


みたいな感じでボタンを設置しておくと、IEでは何のアクションも起こらない。


&#60;button type="submit" value="送信"&#62;送信&#60;/button&#62;


こうやってちゃんと属性を自分でセットしてやらないと、何の役目も果たしてくれないボタンがぽつんと配置されるだけになってしまうようです。
つい最近のことですが、このことを知らなくて、普通にFirefoxでテストしたときにメールの送信ができていたから問題ないな～と思っていたらIEで何のアクションも起こらないよ的な指摘を受けまして……調べてみたらこれが原因だったと。
いやはや……。
]]></description>
			<content:encoded><![CDATA[<p>HTMLにbuttonタグという、ボタンを表示するタグがある。</p>
<p>このボタン、Firefoxだとsubmitが既定値になっているらしいのだけど、IEとかだとsubmitの属性がついていない状態が既定値になっているっぽい。</p>
<p>なので</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

&lt;button value="送信"&gt;送信&lt;/button&gt;

</textarea>
<p>みたいな感じでボタンを設置しておくと、IEでは何のアクションも起こらない。</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

&lt;button type="submit" value="送信"&gt;送信&lt;/button&gt;

</textarea>
<p>こうやってちゃんと属性を自分でセットしてやらないと、何の役目も果たしてくれないボタンがぽつんと配置されるだけになってしまうようです。</p>
<p>つい最近のことですが、このことを知らなくて、普通にFirefoxでテストしたときにメールの送信ができていたから問題ないな～と思っていたらIEで何のアクションも起こらないよ的な指摘を受けまして……調べてみたらこれが原因だったと。</p>
<p>いやはや……。</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/374/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HABTMのページング処理</title>
		<link>http://astrodeo.com/blog/archives/326</link>
		<comments>http://astrodeo.com/blog/archives/326#comments</comments>
		<pubDate>Thu, 14 Jan 2010 10:08:36 +0000</pubDate>
		<dc:creator>マッチー</dc:creator>
				<category><![CDATA[CakePHP]]></category>

		<guid isPermaLink="false">http://astrodeo.com/blog/?p=326</guid>
		<description><![CDATA[通常、CakePHPでページング処理をしたい場合は


$this-&#62;paginate('Model');


で簡単にできる。
HABTMの場合でも基本的にはこれを使えばOKだが、HABTMの中間テーブルのモデルを作ってやる必要が出てきたりするので、ちょびっとだけ戸惑う。
たとえばユーザーとカテゴリを紐づけているcategories_usersというテーブルがあった場合


$this-&#62;CategoriesUser-&#62;bindModel(array('belongsTo' =&#62; array('Category')), false);

$this-&#62;paginate = array(

'conditions' =&#62; array(

'CategoriesUser.user_id' =&#62; 1,

));

$this-&#62;set('data', $this-&#62;paginate('CategoriesUser'));


こんな感じに書くと、IDが1のユーザーが持っているカテゴリの一覧のページング処理ができる。
bindModelが結構大事。ユーザーとカテゴリはすでにHABTMで結びついているじゃんとか思ってbindModelを書かないと、ページング処理は上手くいかない。
もちろん、モデルにCategoriesUser.phpファイルを作るのも忘れずに。
余談だけど、bindModelとかunbindModelって、どうも配列の書き方がしっくり来ないよね…？
]]></description>
			<content:encoded><![CDATA[<p>通常、CakePHPでページング処理をしたい場合は</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

$this-&gt;paginate('Model');

</textarea>
<p>で簡単にできる。</p>
<p>HABTMの場合でも基本的にはこれを使えばOKだが、HABTMの中間テーブルのモデルを作ってやる必要が出てきたりするので、ちょびっとだけ戸惑う。</p>
<p>たとえばユーザーとカテゴリを紐づけているcategories_usersというテーブルがあった場合</p>
<textarea name="code" class="PHP:nocontrols" cols="30" rows="5">

$this-&gt;CategoriesUser-&gt;bindModel(array('belongsTo' =&gt; array('Category')), false);

$this-&gt;paginate = array(

'conditions' =&gt; array(

'CategoriesUser.user_id' =&gt; 1,

));

$this-&gt;set('data', $this-&gt;paginate('CategoriesUser'));

</textarea>
<p>こんな感じに書くと、IDが1のユーザーが持っているカテゴリの一覧のページング処理ができる。</p>
<p>bindModelが結構大事。ユーザーとカテゴリはすでにHABTMで結びついているじゃんとか思ってbindModelを書かないと、ページング処理は上手くいかない。</p>
<p>もちろん、モデルにCategoriesUser.phpファイルを作るのも忘れずに。</p>
<p>余談だけど、bindModelとかunbindModelって、どうも配列の書き方がしっくり来ないよね…？</p>
]]></content:encoded>
			<wfw:commentRss>http://astrodeo.com/blog/archives/326/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
