ゴールデンウィークからWebアプリを作成していました。
どんな風に勉強しながら、どれくらいの時間かけて作成していったかの日記を記しておきたいと思います。いつか技術的なところも別記事でまとめます(たぶん)。
つくったWebアプリ AtCoder Code Evaluate
(2021/8/23: 様々な浅い事情により現在まともに機能しておりません。)
Webアプリの機能(何を実現したかったか)
出来ることは主に以下の3つです。
- AtCoderの問題ごとの実装重さがわかる(かもしれない)
- ユーザーの各問題のACコードのランク評価(コード長、実行時間)
- ACコードのランク評価をもとにしたランキング表示
実装重さ評価
AtCoderの問題はアルゴリズムを考える考察部分と、考え抜いたアルゴリズムを実装する部分に分かれます。
基本的には考察部分の方が重要だと思いますが、時々考察よりも実装の方で苦しむ問題もあります。(実装で苦しむのは考察が足りてないという意見もありますが)
時々ABCのC問題あたりに、やることはわかるけどどうやって実装したらいいのかわからない系の問題がおかれることがあり、その回はC問題の正解者が普段より激減するという現象が見受けられます。
例えばこういう問題です。Syntetic Kadomatsu(この問題自体はだいぶ昔のABCです)
こういう問題に苦しむことが多く、実装の重い過去問題を重点的に解くため、AtCoder Problemsのdifficultyのように、実装重さを一目でわかるようにしたかったというのがやりたかったことの一つです。
ただ、実装の重さをどのような指標で測るかというのが一番難しいところなのですが、あまり難しいことはできないので、今回はシンプルにACコードのコード長を使用しました。
つまりシンプルに、ACコードのコード長が長い = 実装が重いという考えです。
そうでない例は自身でたくさん経験していますが、他にいいアイデアがなかったのでとりあえずこの形にしました。もう少し別の視点も考えて取り入れていきたいなと思っています。
ACコードのランク評価
こちらの記事に記載したような内容です。「AtCoder 提出コードのレベルが高い人を探す」
個人的には実行時間の定数倍改善も大事なスキルだと思っているので、そういうのも駆使しながら常に速い(短い)コードを書くモチベーションにつながるものを作りたかったのいうのがもう一つのやりたかったことです。
ACコードのランク評価 ランキング
せっかくスコアリングするので、どうせならランキングを作ろうと思いました。
全言語共通にすると上位に食い込めるのがほんの数名になってしまい、それだと初中級者のモチベにつながりにくいと思ったので、言語を細かくわけ、総合点だけでなく平均点でのランキングも作成してみました。
開発の日記
ようやく本題です。
開発を始めた際の私のスペックです
- HTML/CSS, JavaScriptをProgateで触った。(10ヶ月くらい前)
- DjangoチュートリアルでなんとなくWebアプリ作成の雰囲気を掴んだ(10ヶ月くらい前)
- N予備校のwebアプリ入門コースでWebアプリ開発の基礎的な知識(通信やセキュリティ等)を学んだ
- PythonでGUIアプリを作成した(オブジェクト指向 MVPアーキテクチャ)。
- PythonでAtCoder水色
- Gitは触るくらいならできる
要約するとアルゴリズムはそこそこわかる。Pythonの基本文法はOK。あとはWebアプリのチュートリアルをかじった程度。というレベルでした。
AtCoder ProblemsのGitHubを眺める(2,3日)
GW突入(4月末)と同時にとりあえずAtCoderProblemsさんのGitHubをみて勉強を始めました。作成するWebアプリのUIとしてAtCoder Problemsさんを真似しようと思ったからです。(私はProblemsさんのUIがとても好きです。)
正直最初は何もわからなかったです。Kenkoooさんのブログを参考に、使われている技術についてGoogle先生の力をフル活用しながら勉強していました。
2, 3日勉強してわかったことは以下のことです。
- フロントエンドとバックエンドを明確に分けて開発する手法があるらしい
- バックエンドはJsonデータを返すだけにして、受け取ったデータをフロントエンドでこねくり回してページを作成するらしい
- JavaScriptのfetch関数などで非同期でバックエンドのJsonを取得できるらしい
- こうするとシングルページアプリケーション(SPA)になってページ遷移を早くできるらしい
- フロントでJsonデータをこねくり回すために、Vue, React, AngularというJavaScriptのフレームワークがあるらしい(ProblemsさんはReactを採用している)
- Jsonデータだけ返すようなバックエンドのことをWeb APIなんて呼んだりするらしい。ProblemsさんはRustという言語で実装しているけど、Pythonでも例えばDjango Rest frameworkを使えば作れるらしい
- たまに聞くAPIを叩くというのはこのWeb APIにリクエストを送ることらしい。
- JavaScriptの上位互換(語弊があるかも)の言語にTypeScriptがあるらしい。フリーダムすぎて扱いに困るJavaScriptに開発者が適度に躾をして扱いやすく出来るらしい
知らない概念が山ほど出てきて非常に新鮮でした。
以上を踏まえた上で、今回作るWebアプリはフロントエンドにTypeScript + React、バックエンドにPython + Django Rest frameworkを使うことを決めました。
フロントエンドはProblemsさんがTypeScript + Reactを採用していたのでそのまま真似することにし、バックエンドは流石に0からRustを勉強する時間はなかったので、Pythonをベースに有名そうなフレームワークを選択しました。
フロントエンドの勉強(1週間)
とりあえずフロントエンドからやると決めて、TypeScriptとReactの勉強を始めることにしました。
結構つまづいたのが環境構築です。フロントエンドの環境構築はかなりややこしく感じました。
ややこしそう→失敗してローカルPCの環境をめちゃくちゃにしたくない→そうだ仮想環境使おう!ということでついでにvirtualBoxやDockerについても勉強し始めました。
とりあえずvirtualBoxを使っておけばローカルの環境が汚染されることはなさそうだったので、チュートリアルでの勉強や実際の開発でもvirtualBoxだけを使用しました。(virtualBoxを使っておけばDockerは不要かなと思ってたんですが、ついでに使っておけばよかったかもしれません)
TypeScriptとReactはそれぞれ公式のチュートリアルをさらっとやりました。また、そもそもJavaScriptの知識もProgateどまりだったので、基本文法もこちらのサイトを使いながら勉強していました。なお、Reactはクラスベースではなく、Hooksの書き方を主に勉強しました。なぜなら公式がHooksを推奨していたからです。
やはり画面に大きく変化があるというのはわかりやすい報酬なので、実装しては画面の変化をみて感動するというのを繰り返しながら遊んでいました。
フロントエンドの実装(骨組みだけ)(1週間)
チュートリアルで雰囲気がつかめたので、とりあえず自身のWebアプリ用に実装を始めることにしました。
環境構築はAtCoderProblemsさんのGitHubのコードを参考に、わかる範囲でいじってやりました。基本はreact scriptを使う前提で構築しているので、webpackやbabelの設定については一切触っていません。(気持ちがわかる程度には勉強しましたが、とりあえず自分向けにカスタマイズする必要性を感じなかったです。たぶんカスタマイズの必要性を理解していないだけだと思います・・・)
APIはまだないので、ある前提でJsonデータを定数として宣言しておいてReactのコンポーネントにpropsとして渡す形で、データの整形や、表示の骨組みだけ実装していきました。
見た目についてはMaterial-UIを使うことにしました。(なんとなく)ただ、CSSを最初にじっくり調整して、後々再調整するのはいやだったのでとりあえず最低限だけ設定して超シンプルな見た目で実装しました。
たしかこの辺りでGWも終わったと思います。GW中にある程度形にしたいと思っていたんですが、全然間に合わなくてやはり経験値がたりなさすぎて工数の見通しを立てるのは難しいなと感じていました。
データの集計・解析(1週間)
問題ごとのACコードのコード長中央値などを集計・解析する必要があったので、Pythonで実装しました。
最初、データを集めるところをスクレイピングでやろうとして実際実装して動かしてみたのですが、データ数が膨大すぎて全部の提出データをあつめるだけで1週間近くかかるペースでした。(リクエスト間隔を2秒とっていました。あまり短い間隔でリクエストを送ってAtCoder社に迷惑をかけるのだけは避けたかったので)
どうしたものかと考えてAtCoder ProblemsさんのGitHubを眺めてみたらなんと欲しいデータセット(全ユーザーの全提出コード)がまるっとcsvで公開されていました。
データさえあれば、解析するだけならそれほど時間はかからないので、こちらの記事で記載したような感じで解析を行いました。
やや遠回りもしましたが、スクレイピングでwebページからデータを集めてくる作業はハッカー気分になれて楽しかったです。
バックエンドの実装(1週間)
冒頭に記載した通りDjango Rest frameworkを使ってWeb APIを実装しました。
Pythonならそこそこわかるからスムーズにいけるだろうと、かなり油断していたのでチュートリアルなどはやらずに、最初から自身のwebアプリ用に実装を行いました。しかし、やはりPythonどうこうというより、フレームワーク自体の知識がないとさっぱりわからないので、当初の見込みよりは苦労しました。
普段は公式サイトをとりあえず眺めるタイプなんですが(説明書を読み込むタイプ)、Django Rest framework に関しては以下の書籍を購入して勉強と並行して実装を行いました。全体像の把握を重視しているような書籍で、自分が今何をやっているのかわからなくなりがちなwebフレームワークの勉強においては、とても助かる書籍でした。
今回はとてもシンプルなモデルが5つで、モデル間のリレーションもシンプルだったため、書籍で紹介されている範囲で十分に実装可能でした。
一番困ったのはデータベースへのデータ投入方法で、ユーザーからPOST、DELETEされることはないものの、数百万行のデータをcsvとして持っている状態から、どうやってデータベースに初期データを入れればいいのかという地味な箇所でかなりの時間をくいました。
最終的にはcsvを読み込んでまとめてデータベースに保存するスクリプトを作成して、Django Shellで実行するという結構強引な手法で大量のデータをデータベースに投入しています。
フロントエンドとバックエンドをつなげて色々と調整(1週間)
APIができたので、フロントからJsonを取得して画面に反映させるところを実装しました。
非同期処理でJsonデータをとってくるところの処理でつまづいたり(プロキシの設定や再レンダリングの仕組み)、思うようにレイアウトが調整できなかったりでここでも大変苦戦しました。
非同期処理に関して最初はuseEffectを使って実装していたんですが、あまり上手に実装できなかったので、Problemsさんの実装に倣ってreact-refetchというパッケージを使ってAPIを叩く部分を実装しました。
また、データが増えたことでレンダリングに時間がかかるようになってしまったため、高速化のために、データ整形のためのアルゴリズムを見直したり、Reactでのレンダリング最適化について勉強しながら、サクサクページ遷移できるように調整もしました。この辺の高速化に関してはかなり競技プログラミングの経験が活きたと思いますし、ちょっと競技プログラミングっぽくて面白かったです。
完璧を目指すよりはとりあえず公開まで持っていきたいという思いもあったので、満足いかない部分もたくさんありましたがほどほどで妥協しながら先に進めていきました。
世界に公開!!(2週間)
とりあえず形になったので、公開することにしました。(デプロイと呼ぶようですね)
様々な公開方法があるようでしたが、以前から興味があったと言う理由でAWSを使ってみることにしました。
AWSについて調査・勉強しながら、基本的なサービスを使いつつ、なるべく色々なサービスを触ってみたいなという思いから以下のような形でデプロイすることにしました。
- フロントエンド: S3 + CodePipeline + Route53 + CloudFront + Certification
- バックエンド: EC2
バックエンドはAWSに限らないインフラの知識にもなるなと思ったので、EC2コンテナにNginx + gunicornでWebサーバーを立てることにしました.
おそらくこの公開作業が一番苦戦したと思います。
開発時はCORSエラーをプロキシで回避できていたのができなくなったり、フロントだけhttpsにしてバックエンドはサボっていたらMixed Contentエラーがでたり、EC2のhttps化がCertificationでできなかったり、Route53をつかってドメイン名をつけてるとcertbotでhttps化するのも手間がかかったたり、NginxのCORS設定がうまくいかなかったりなどなどなどなど、初めての経験ばかりでした。
ただ、インフラの勉強もとても面白かったです。結構表面的なところの勉強になってしまっているので、もっと基礎的なところからじっくり勉強していきたいと思っています。
また、AWSについても様々なサービスがあるようなので積極的に色々さわりつつ。資格もあるみたいなので体系的な勉強も兼ねて今年中に資格を取得してみようかなと思っています。
まとめ
だいたい2ヶ月弱かけてwebアプリを作成・公開してみました。
PythonでGUIアプリを作った時にも感じましたが、やはり何かを作ってみるというのはとても勉強になって楽しいです。
今の所は次これを作りたいというものがないので、色々調べ物しながら次何をするか考える予定です。
コメント