みんなの「作ってみた」

1日で作れるWebサービスを作るのに1ヶ月かかった話

2018/12/22

defunty
defunty

この記事は個人開発 Advent Calendar 2018の19日目代打記事です。

はじめに

今回初めて趣味で作成したWebサービスの人月が、見積もりの30倍となってしまいました。
この記事では、これから初めて個人・少人数でWebサービスを開発する方に反面教師の失敗談として共有して頂くことを目的としています。

見積もりを誤った人のスキル

趣味でプログラムを書いているだけのHTMLコーダー(3年目)です。
「デザインのできないデザイナー」のようなものとお考えください。

プログラムは独学ですが、CentOS上でLAMP環境のCRUD機能を持つアプリケーション程度であれば作れます。
(セキュリティについても考慮できていると思います)

モダンな開発方法については一通り分かりません。

1日でできたはずの成果物

ネット上のWeb系求人情報をもとに、プログラミング言語ごとの求人比率を可視化するWebサービス Dekill を作りました。
自分の持っているスキルセットの需要や現在需要の高いスキルを簡単に確認することができます。

比較対象となる技術、Web系以外での職種については今後増やしていく予定です。

開発前の見積もり

  • 情報のスクレイピング:「経験がないので不明。4時間くらい?」
  • バックエンド:「スクレイピングで格納した情報をよしなにするだけなので1時間。」
  • コーディング:「チャート表示ライブラリを利用すればすぐ終わりそう。2時間。」
  • デザイン:「デザインは門外漢なのでまずは気にしない。30分」

以上、8時間ほどあれば形にはなるだろうという認識でした。
まずこの時点で意識しなければならなかったことは、趣味でやるからといって見積もりを適当にしてはならないということです。

仕事での見積もりにミスがあるとチームに迷惑をかけてしまいますが、趣味での見積もりを見誤ると自分に迷惑をかけることになります。
他人に迷惑をかけないことは大事ですが、自分に迷惑をかけないことの方がよっぽど重要であることを忘れてはいけません。

できあがるまで

言語の選択

一番慣れている言語はPHPでしたが、このアプリケーションの最終目標はデータ分析を行うことにあります。そのため、データ分析に関するライブラリに富んだPythonのフレームワーク、Djangoを利用してアプリを作ることにしました。実際、Pythonのライブラリ群は私のイマジネーションを大いに励起してくれました。

機能的にはPythonのマイクロフレームワーク、Flaskの方が適切に思えましたが、Djangoは並行して開発しているアプリケーションに利用していたので今回の開発を容易にするためにDjangoを選択しました。
(後述しますがこの検討は最終的に意味を成しませんでした)

スクレイピングの法的解釈

スクレイピングについて真っ先に私が思い浮かべたものは、「岡崎市立中央図書館事件」でした。
OPACをクローリングしたら逮捕されるこの国で - 図書館退屈男
不起訴とはなったもののスクレイピングを行ったことにより逮捕者が出たこの事件については知っていましたので、どのようにスクレイピングすれば法的に問題ないかを調査する必要がありました。

サーバーへの配慮

プログラムを用いた短時間での連続的なアクセスはサーバーに余計な不可がかかります。
サーバー管理者の方に迷惑がかからないよう、常識的な間隔でアクセスを行う必要がありますので、私はアクセスの少ないであろう真夜中の時間帯に5秒間隔でアクセスを行うようにしました。
(ただし5秒という数字に法的根拠はありません)

スクレイピングしてよいコンテンツ

スクレイピングは、第三者のサイトのコンテンツを利用する形になります。これは著作権的に問題ないのでしょうか。
著作権法47条の7によると、

著作物は、電子計算機による情報解析(多数の著作物その他の大量の情報から、当該情報を構成する言語、音、影像その他の要素に係る情報を抽出し、比較、分類その他の統計的な解析を行うことをいう。以下この条において同じ。)を行うことを目的とする場合には、必要と認められる限度において、記録媒体への記録又は翻案(これにより創作した二次的著作物の記録を含む。)を行うことができる。ただし、情報解析を行う者の用に供するために作成されたデータベースの著作物については、この限りでない。

とありましたので、今回の求人情報件数の取得においては著作権違法にはあたらないと判断しました。

また、スクレイピングを行ってはならないサイトについては利用規約に書かれていることが多いのですが、利用規約を見ずに閲覧可能なコンテンツについては利用規約が適用されないため、利用規約が表示されない範囲でのコンテンツ取得を行うこととしました。

どうでもいい話ですが、「ペッパー君に決まったキーボードを押させてWebページを表示させることはスクレイピングにあたるか」という内容について2時間程考えました。:frowning2:

スクレイピング処理作成

スクレイピング処理については一般的なやり方です。Seleniumでブラウザを自動操作し、Beautifulsoupwpをパーサーとして利用しました。

初めはBeautifulsoupだけで対応する予定でしたが、対象サイトによってはページのレンダリング後に件数を表示するものあり、レンダリング後に一度スリープさせて件数取得処理を行う必要があったためSeleniumを併用しました。

参考にするための記事が多く、思ったよりも簡単に対応することができました。
(ここで初めてスムーズに事が運びました!)

サービス名を考える

スクレイピングテストの待ち時間の間、サービス名を考えることにしました。
適当に考えをめぐらせ
Demand(需要)+ Skill(技術)= Dekill(できる)
という親父センスのみなぎる名前を思いつきましたが、この名前は私の中で非常にしっくり来たため10分程で決定しました。

インフラ環境を決める

私は今までプロダクション環境についてはレンタルサーバーとVPSしか触ったことがなかったのですが、現在の開発者の中ではVPSというとCOBOLのようなレガシー扱いになっているようで、良い機会なのでクラウド環境に手を出そうと考えました。

私の中でAWSHerokuが一番聞き覚えのあるワードだったので、環境構築が簡単でスケールアップしない限りはサーバー代が安く済む(と思われる)Herokuを選択し、またRDBMSのこだわりはなかったのでHerokuでデフォルトのように思えるPostgresを利用することにしました。

Herokuの導入

Herokuへのデプロイは非常に簡単でした。Herokuへの登録・CLIツールの導入後、Herokuで用意されているDjango用のサンプルアプリをcloneし、自分のHeroku環境へデプロイすれば終わりです。
ただ、サンプルアプリには私が必要としない機能が入っているため、私は一から作成したDjangoアプリをHerokuにデプロイする必要があったのですが、HerokuのTutorialでは通常のDjangoアプリに加えて何のファイルを用意してあげれば良いのかが理解できませんでした。

また、私はPython(Django)初心者なので、Herokuのサンプルアプリを眺めてどのファイルがDjangoにとって特別でHerokuにとってデフォルトなのかを判断するのに時間がかかりました。(結局はProcfileとrequirements.txtをHerokuに用意してあげれば良いだけの話でしたが)
更に、私は単独でしか開発を進めたことがなく、gitのリモートリポジトリの概念を理解しておらず、Herokuにデプロイをする上でファイルコンフリクトやリポジトリの紐付けに関して都度問題が発生し、解決に時間をかけることとなりました。

このあたり、プログラマーの皆さんは当たり前にgitを利用されているので、私のセンスの無さによるものと、人に質問しなかったのが問題だと考えています。どうしても分からない場合は周りの人に聞くかTeratailなどで質問してみるべきです。
初心者の方は、どうか怖がらないで!:ghost::ghost::ghost:

Postgres用のキャッシュサーバーも立てたい

Herokuやgitの学習を終えた私は調子が出てきたのかキャッシュサーバーの利用も考えました。(もちろん利用経験は0です)
大量データをスムーズに捌くシステム構築は憧れの存在というのもあったのですが、このあたりから「どうせ1日で終わるような簡単な開発だから、使ったことない技術を使っていこう!」という意識になっていました。
開発を初めて既に一週間経過しているのですが。

Redisとの出会い

そのような流れで出会ったキャッシュサーバーのRedisに私は一目惚れしました。
Redisの学習コストの低さ・取り扱いやすさ・柔軟さなど、様々な要素が私を夢中にさせました。
Redisの素晴らしさはこの記事の一端で語るべきではありませんが、私はRedisをPostgresの代わりに利用しようと決めてRedisに関するドキュメントを読み漁るようになりました。

今となってはRedisは本プロジェクトの傾国とも言えます。
Redisとのランデブーは10日程続きました。:couple_ww:

Redisとの別れ

ある程度Redisについて学習したのでデータの制御処理を構築しました。Redisの学習期間を除けば、(いちおう)見積もり通りの1時間で対応できました。
ですが、ローカルからHerokuにRedisのデータを移行しようとしたところ、Heroku Redisのhobby(無料)プランではRedisに永続性を持たせることができないことが分かりました。つまり、サーバーが落ちたりメモリが不足するとHeroku上のRedisデータは抹消されます。

Redisに永続性を持たせる場合、最低でも月額15$がかかります。これはPostgresのhobbyプランの従量課金満額よりも高額で、求人件数を取得して表示するだけのアプリにこれほどのコストはかけられないため、泣く泣くRedisの採用を諦めました。:cry:

※Redisは暗号化の機能を持っていないため個人情報を持たせるには適していません。基本的には「消えても良い」・「見られても良い」・「データ同士のリレーショナル性が低い」といったデータを取り扱うべきです。
追記:暗号化の機能を持っていないだけで、自前で暗号化することは可能です。また、Amazon ElastiCacheのRedisでは暗号化に対応しています。

Herokuの料金体系の思い違い

更に悪いことに、Herokuコンテナのhobby(月額7\$)プランはアカウントではなくアプリごとに設定するものだと分かりました。
私の当初の見積もりでは、

Herokuコンテナ(7$)+ Postgres(アプリ * 0〜9$)

だと考えていたのですが、実際のところは

Herokuコンテナ(アプリ * 7$)+ Postgres(アプリ * 0〜9$)

となります。

私としては開発したいアプリがあと一億個程ありますので、Herokuでの運用を見直すことにしました。

Netlifyで良いのでは?

このあたりでモチベーションが底を尽き始め、プロジェクトが自然消滅パターンに入る予感がしていたので、とにかく作って出さねばと思い、10点でもいいから出すことを目標に進めるようにしました。

そこで、爆速開発でおなじみのNetlifyを利用することを考えました。
今回の要件であれば、求人情報データをローカルで取得しておいて、静的にデータを記述してgithubにデプロイしたものをNetlifyで配信するようにすれば対応できそうです。
早速試してみたところ、10分でできました。すごい。:zap::zap::zap:

そんなこんなで完成しました。

利用規約は?

利用規約を作らなければと思いましたが、先述したように利用規約をコンテンツの前に挟む余地がないため、対応しませんでした。
利用規約ページが必要な場合は雛形が用意されているサイトもあるため、そちらを活用すると良さそうです。

今後やること

比較対象技術の追加

今は利用言語での比較ですが、各種フレームワークやインフラサービスに関する項目も追加します。
各種技術のカラーコードを被らないように決めるのが地味に辛そうです。

求人データの別表現

ある程度求人データが溜まったら求人件数推移表のような形で色々な観点から情報が見られるようにしていきます。

ページ表示速度のチューニング

表を一つ出す程度のアプリで満点を取れないのはダメだと思います。

デザイン

:thinking::thinking::thinking:

おわりに

  • 個人開発したかったけど作りきることができなかった

    • 分不相応に立派なものを作ろうとしていた
    • マイクロなサービスにしたら初めてやりきれた
    • 予想の30倍時間かかったけど
  • 分からないことが多くて思うように進まない

  • アーキテクチャは魔の山

    • 「最適なアーキテクチャ」を考えるのはほどほどに
    • 火のないとこに煙は立たない
    • データのないとこにサーバを立てない
  • 趣味開発をきっかけに新しい技術を習得したい

    • 使ったことのない技術の採用は一つまでに抑えるべき
    • むしろリリースまでは使ったことのない技術は使わなくて良い
    • リリース後、機能拡張しながら使える技術を増やしていく経路もある