2019/03/22
先日、ひとり旅のための宿検索サイト「ソロ旅ねっと」というサービスを公開しました。
ソロ旅ねっとは、複数地域、複数の宿泊予定日を自由に組み合わせて、一人宿泊が可能な旅館、ホテルを検索できるサービスです。このサービスをまじめに考えだしたのは2018年の12月初旬で、ソースを書き始めたのは同年12月の下旬頃です。
ソースコードの最初のコミットから3か月、最初のリリースからも約2か月が経ったので、これまでを振り返りつつ、宣伝もかねて、今回は、サービスを作ろうと思った経緯、サービスの中身の話などを、サービスの紹介と合わせてお話ししたいと思います。
僕は割と一人での旅行(特に温泉地)が好きで、年に数回、どこかの温泉地に赴き、1~2泊で、ひたすらダラダラするのを生きがいの一つとしております。
泊りで行くので宿泊場所は事前に取らなきゃアカンのですが、既存の宿泊施設検索サイトで宿探しをするのはとてもとても使いづらい&面倒くさいのです。
そこで、僕が使いやすいサービスを作ってみようと思ったのがきっかけです。
「来週か再来週あたりの金曜日に、北の方の温泉地に行ってみたい」という条件で、宿泊施設を探そうとすると、既存の宿検索サイトはとんでもなく使いづらいです。
宿泊施設検索サイトは、楽天トラベル、じゃらん、JTB、など、いくつもありますが、どのサイトも目的地をきちんと入力しないと検索できないようになっております。
しかも、「北の方にある温泉地」などという曖昧な表現ではだめで、○○県××市、だとか ○○温泉、などという感じで目的地をかなり正確に限定する必要があります。
僕は旅館・ホテル検索サービスを運営しているようなところで働いた経験がないので完全な憶測になりますが、そのようなサイト設計になっている原因はいくつか推測できます。
検索サービスに入ってくる人の大半は、観光で行きたい場所などの目的地は完全に決まっている。
この場合、わざわざ広範囲での宿泊施設検索を用意する必要はありません。
内部管理している宿泊施設データが、地域をキーとして検索されることを前提として設計されている。
複数地域をまたいだ検索を実装した場合、クエリーが複雑になったり、サーバに負荷がかかったり、十分な応答性能が出せない可能性があり、簡単に実装することができない。
サービス公開後のシステム設計の変更ってとんでもなく大変なのです。
大雑把な地域でも細かい地域でも検索できる、見栄えが良く、使い勝手の良いUI/UXを提供するのは確かに難しいと思います。
複数の地域を色々選べるようにしても、エンドユーザさんが使いこなせなかったり、条件指定がめんどくさくて離脱してしまっては元も子もありません。
宿泊施設から掲載料とは別にお金をもらって、地域ページのサイドバーに「おすすめの宿泊施設」として特定の施設を常時表示させたり(広告)、お金をたくさん支払ってくれた宿泊施設を検索結果の上位に表示させたりといった施策がとられていることもあると思います。
しかし、それゆえに複数地域をまたいだ検索コンテンツは提供しづらい(サイドバーのおすすめに何を出すか、表示順位をどうするかなどの問題)。
この辺あまり詳しくないのですが、サイトトップ > 都道府県 > 市区町村 > ホテル一覧 みたいなきれいな構造になっていた方がSEO上有利、なのかもしれません。
ただ、エンドユーザさんの使い勝手を犠牲にしてでも、検索エンジンには気を使うという設計方針が選ばれているんだとしたら少し残念と感じます。
いよいよ年末の2018年の12月初旬、お正月明けの温泉旅行プランを妄想しつつ、使いづらいと思いながらも楽天トラベルで宿検索をしておりました。その時に、作れそうなら、自分が使いやすいと思うサービスを作ってみてもいいかな、と思い、調査を始めました。
楽天が開発者向けに楽天市場の商品検索APIを公開しているのは知っていたので、楽天トラベルの情報もとれるのではないかと思い調べてみました。
楽天Webサービス:API一覧
ドキュメントを確認したところ、楽天トラベルの施設検索、空室検索もAPIとして提供されていました。
そこで、今回はこちらを利用させていただいて、一人旅専用の旅館、ホテルの検索サービスを作ってみることにしました。
なお、あとで知ったのですが、同様のサービスがじゃらんからも提供されているようです。
楽天が提供しているAPIを利用させていただくため、楽天が提供していない機能、規約違反になってしまうような機能は提供できません。
それを踏まえたうえで、APIドキュメントを読みつつ、どれくらいのことができそうかを決めていきます。
「できそうなこと」でも書いていますが、このサービスを実現するには、宿泊施設の情報、空室状況を、常に更新していく必要があります。そして、それを実現するには結構な回数のAPIコールが必要です。
例えば、空室状況の更新を10日に1回とした場合、データ取得&検索タイミングによっては、すでに予約でいっぱいな施設だらけになってしまうかもしれません。
最終的には、
などを考えつつ、システム仕様に落とし込んでいきます。
ちなみに、ソロ旅ねっとでは、約5週間後までの空室状況を1日~数日おきの頻度で更新をしています。
平日の巡回頻度は少なめに、休日、特に連休日の更新頻度は多めにする等の、調整を行うことで、できるだけ長期間の空室状況を取得できるようにしています。
また、楽天トラベルには一人宿泊が可能な宿泊施設が1万~2万件ほど登録されています(事前に1回クロールして調べた)。
これを踏まえると、空室状況を各施設に設定されているプラン毎に保存する場合、テーブルのレコード数は100万以上になる可能性があります。
宿泊施設データ(約1万~2万)はともかく、空室状況データの100万レコードを1つのテーブルに格納するのは多少サーバにお金をかけないと厳しいかもと思ったので、空室状況テーブルのデータはパーティショニングした方がよさそうです。
要件が固まってきたので、言語は何にするか、DBはどうするかということの検討に移ります。
利用規約に、「一般に公開されていないサイトでの利用は不可」との記述があるため、僕専用サービスとして、ずっとlocalhostで動かし続けるわけにはいきません。
また、収益化できているというのも、開発モチベーションとしてはとても大事なことです。
現状の収益化手段は、楽天アフィリエイトプログラムです。
運よく利用者が現れて、サイト経由で予約が成立すれば、楽天アフィリエイトプログラムにより収益が発生するようになっています。
が、現状では、需要があるか、人が来るか等、まったくわからないため、コストはできる限り抑えたいです。
とはいえ、ある程度のレスポンス速度はやっぱり必要なので、その辺のバランスを考えて、ソロ旅ねっとは今のところ以下のような構成で運用しています。
サービス運営に直接かかった費用だけを考えれば、損益分岐点は3年で1万5千円~1万8千円程度となります。
予約1件あたりの収益を100円(楽天アフィリエイトの収益は、予約金額の1%)程度で計算しても、少なくとも送客数150人から180人は必要です。
過疎ったら確実に達成できない。過疎らなくても難易度は割とハードな気がします。
少なくとも、確定申告が必要になるくらい稼ぐのは難しそう。
自分が欲しいからという動機づけがなければ、この時点で計画倒れとなっていたと思います。
gitリポジトリ名をどうするか、という問題もあったため、サイト名は最初に決めました。
名前を決めるために考えたことは以下の4つです。
特に商標は、権利者がいた場合とんでもなく面倒くさいことになりそうな気もしますし、事前に確認するのは大事だと思います。
ちなみに登録済の商標は 特許情報プラットパット、で簡単に検索することができます。
gitリポジトリへの最初のcommitが2018年の12月20日、1stリリースが2019年1月27日なので、開発期間は1か月ちょっとでした。開発は、会社の昼休み、平日帰宅後にすこし、休日予定がなかった時に進めていました。
業務時間中も、どんな感じで実装していこうかっていう妄想くらいはしていたかも。
サーバ側の実装に関しては、今更困るようなことは特にありませんでした。
slim(フレームワーク)を使おうかとも思ったけど、完全に理解しているわけでもないし、ハマった時の調査とか面倒くさかったので、お手製のMVCフレームワークもどきを作成&使用しています。
なお、外部のライブラリ、モジュールを全く使っていないわけではなく、例えば、template engine として twig を利用しております。
DB接続まわりについては、PDOを直接利用することにしました。Lalavel等を組み入れてもよかったのですが、slimと同様の理由で使用していません。
デザインセンスがあるわけでもなく、cssにさほど詳しいわけでもなかったため、ここはかなり試行錯誤で進めていました。
サービスを公開したのは、金曜日深夜(土曜日早朝近く)、仕事では絶対に選びたくない曜日&時間でした。
割とぎりぎりまでコードを書いていて、公開直前に、awsのインスタンスの購入やドメイン取得&設定を行いました。
この時点まで、Linux環境で全く動かしていなかった(Windowsのローカル環境使ってました)ため、ハマったらその日の公開はとりあえず諦めるつもりでいましたが、特にトラブルもなく、無事に公開までこぎつけることができました。
サービスの公開以降は、ユーザさんの反応やGAなどを確認しつつ、改善していくのがセオリーだと思うのですが、PVが全然ないし、自分が作りたいと思ったこともまだまだできていないので、現在は、その辺の実装もやりつつ、最低限の環境整備的なことをやっています。
機能追加、性能改善以外では、以下のようなことをやっていました。
さすがにテスト環境も必要だと思い、本公開後に準備しました。
といっても、テスト時だけ立ち上がるinstanceなどを用意したわけではなく、本番環境の別portがテスト環境になっています。
会社で同じことやったら、方々からアホといわれること間違いなしです。
初回リリース直後は、毎回WinSCPを立ち上げてファイルのコピーというとても残念な運用をしていました。
さすがにそれはやめましたが、今でも割と残念な運用をしています。
CI使って、テストにpassしたらデプロイするとかの仕組みを作るのが割と当たり前なんでしょうけど、個人で作ったオレオレサービスだし、いろいろ設定するのも面倒くさい、とはいえ scpで毎回アップロードするのも面倒くさいので、rsyncするだけのスクリプトを組んで、リリース時はそれを流しています。
#!/bin/bash
cp .key/solotabiproduction.pem ~/
chmod 0600 ~/solotabiproduction.pem
composer update
rsync -arvz --exclude 'composer.*' --exclude='.*' --exclude '*.bat' --exclude='environment' --exclude '*.sh' --exclude 'cache' --delete --partial --progress -e "ssh -i ~/solotabiproduction.pem" ./ ubuntu@ec2-**-**-**-**.compute-1.amazonaws.com:~/webroot/
rm ~/solotabiproduction.pem
開発環境はWindowsなので、別途以下のような deploy.batを用意し、実際のリリース時にはこちらのバッチをたたいています
(上のスクリプトでわざわざ .pemを HOMEにコピーしているのもWSL使っているため)
wsl bash ./deploy.sh
お手軽ですが、このやり方ではリリース中にサーバのソースファイルが中途半端な状態になり、更新中にサイトが500になる可能性が非常に高いです。
instanceをRoute53にぶら下げて、リリース時に向き先のインスタンスを切り替えるとか、サーバの別ディレクトリに全ファイルをアップロードし、サーバ側でリネームする、などで、ダウンタイムをなくす or 減らすことはできますが、そういうのは人がたくさん来るようになったら考えることにしています。
なお、stage.batというバッチファイルもあり、これを使えば(以下略
一応、はてなブログにも記事書いてみました。
一人旅愛好家のための宿検索サイトを作ってみた
コピペ記事ではないです。ちゃんと完全書下ろし。
力尽きたので、この辺で終了です。
もうちょい内部の話とか、PHP製のなんちゃってMVCフレームワークの話とか、気が向いたら書くかもしれません。
→ 技術書典7にサークル参加します。のらぬこハウス@い32C でお待ちしております。
最後に
バックエンド、フロントエンド等はあまり問わず、開発系のお仕事ができる会社をゆるーい感じで探しています。何かあれば、twitterのDMあたりで@noranuk0宛に送っていただけると嬉しいです。
それでは、ごきげんよう。