概要
ハックツハッカソン アロカップに出場してきましたが、反省点がたくさんありましたので、Qiitaに備忘録として残しておこうかなと思います。
ハックツハッカソンって?
ハックツハッカソンとは株式会社ハックツさんが開催しているハッカソンです。食費宿泊費が無料で、エンジニアが楽しく、快適に開発できるハッカソンです。個人的に何度も出場させていただいているハッカソンで、ものすごく楽しいので、よく福岡まで行って参加しています。
この記事を書こうと思った背景
実は今回、後輩2人を含むチームが最優秀賞を受賞しました。
プロダクトの詳細についてはこちら(Topa'z)にまとめられています。たくさんの工夫がまとめられているので、ぜひご覧になってください。
このチームが作ったプロダクトは、素晴らしい作品であり、ハックツハッカソンで最優秀賞を取るに値する作品であると思っているのですが、やはり同じ団体に所属している先輩としては悔しい思いもあります。逆に私は今回のハッカソンで失敗しちゃったと思う節があるので、それをまとめて自分への戒めにしようかなと思います。
先に今回作ろうとしたアプリケーションとその構成
今回のハッカソンでは今話題になっている回転ずしチェーン店に乗っかろうとして、幸せな投稿しかできないSNSを作ろうと目指しました。
構成は言語はTypeScriptで統一して、フロントエンドをReact + MaterialUI + Styled Component、バックエンドはNode.js + MySQL on Azure, Prisma, GCP,という感じです。フロントはシンプルな構成にして、できるだけ工数を減らせるようにしました。特に、MaterialUI +Styled Componentで簡単にデザインができるようにしました。ただ、この組み合わせがフロントを書いていた人曰くあまり良くなかったらしいです。ただ、詳しい部分まで把握できてないので、詳細は省きます。今後は別の方法を模索するかもしれません。
バックエンドは私が担当しました。Node.jsサーバを作っていろいろ遊んでみたかったので、このような構成にしました。Azureにデプロイしたのはハックツハッカソンの協賛企業であるAlterboothがAzureのクレジットを提供していたからで、GCPを利用したのはBlobの保存が楽だったからという理由です。Prismaを用いたのはこれがNode.js ORMであるからです。
今回の反省点
今回の反省点をリストにしてみました。
- デプロイができなかった。
- 正直精神的にブラックアウトしそうになった。
- 睡眠時間不足
- 非同期処理の書き方がうまくいかず、断念した箇所があった
- フロントエンドのレビューができなかった。
- フロントエンド、バックエンドの区切りを上手く作れなかった。
- 準備ほぼゼロの状態で初めてNode.jsサーバを作って失敗した。
- ハッカソンで勝ちたいか、失敗でもいいから技術的に挑戦するか
- いかに使ってみたいと思われるアプリケーションを作るか
1. デプロイができなかった。
デプロイが出来なかったというのはフロントエンド、バックエンドともに課題点がありました。まずフロントエンドからです。
1.1 フロントエンドでデプロイができなかった理由
理由はfsというライブラリを用いていたからです。
もっと正確に言うと今回用いたface apiというライブラリがfs(File System)というライブラリを利用していました。ミスが起きた最大の原因はローカル環境ではエラー(警告かもしれないです)を吐きながらも正常に動いていたので、デプロイしても問題ないだろうと判断したことでした。
結果的にその判断が間違いで、NetlifyのBuildでエラーを吐いてデプロイができなかったです。
当然の結果といえばそうなのですが、Next.jsなどのサーバー機能を持ったフレームワークに早いこと移行しておけばよかったと後悔しました。私自身もNext.jsでFile Systemを用いて開発したことがあったので、傷が深くなる前に対応しておけばよかったです。
1.2 バックエンドでデプロイにてこずった理由
バックエンドはちゃんとデプロイできました(2日目の深夜に)。。。。。。。。。
これが今回のハッカソンにおける最大の失敗点です。今回の私の構成は特殊というわけではないですが、それまでにいろいろな過ちを犯しながらこの構成に至りました。私のバックエンドの知識不足をここにちょっと書いておきます。
まず、ORM(Object-Relational Mapping)を使うことが初めてであったため、右も左も分からない状態でした。
最初に私が思いついたことはNodeサーバにSQLiteを載せてそれをデプロイすればいいのではないか!ということです。ただ、この構成はそもそも特殊で、さらに運用が難しすぎるのと、今回の私の使い方では重大な欠陥があるという悪いところ3点セットの構成でした。
その欠陥とは、Azureに対してGithub Actionsを用いてデプロイするのですが、その方法がGithubレポジトリをZip化して、それを送信してAzureで解凍し、その後Buildをするという方法でした。
つまりこの方法ではせっかくAzureで運用しているSQLiteを破壊することになります。このことに気づいてからいったんこのこの方法を捨てました。ハッカソンといえど、本番環境で使えないものを作ることはあまり意味がないと思っているので、方向転換です。この時点で1日目の夜です。
そこからMysqlをAzureに作って、バックエンドがAzure上のMySQLと通信することにしました。ただ、これのデプロイにてこずることになります。
それまでSQLiteを載せたままデプロイできていたプロジェクトがなぜかSQLiteを除けた瞬間デプロイできなくなったのです。このなぜかできないデプロイによってまた1日溶かしました。
ORMではmigrationという作業が必要です。migrationとはDBに保存されているデータを保持したまま、テーブルの作成やカラムの変更などを行うための機能です。
Schemaを書いてそれに従ってデータベースを初期化してくれる機能も含まれているので、最初に一度実行してその後はSchemaの定義が変わった時に使えばいいコマンドです。ところがなぜか私はローカルでmigrationを実行して、AzureのMySQLを初期化して、デプロイされたNodeサーバからもう一度migrationをしようとしていました。つまりあまり意味のないmigrationを脳死でやっていた訳です。ちゃんと自分が行っていることは把握すべきですね。。。兎にも角にも本番環境でmigrationをするのはいいことなのかどうか分からないですが、少なくとも必要のないことでした。そのことに気づかず、永遠にGithub Actionでmigration系のエラーと戦っていました。
結局デプロイはできました。メンターさんにもたくさん協力していただいたのですが、私自身がそのチャンスを上手くいかせず、結局デプロイできたのは2日目の夜。ハッカソン終了まで残り12時間というところでした。
あれ?これ自分がチームの足をめっちゃ引っ張ってるんじゃね?とその時の私は思い始めました。実はその通りなんです。詳しくは次の章で書きます。
2. 正直精神的にブラックアウトしそうになった。
これまで私はハックツハッカソンに3回参加してきたのですが、そのその全ての回で入念に下準備をしていました。ハッカソン当日を迎えるまでにコア機能をしっかりと実装して、絶対にこけることの無いようにと心掛けていました。
しかし、今回、その準備を怠りました。そしてその結果、不慣れなバックエンドを書き、上のような状況になりました。自分自身のメンタル的な問題になってくるのですが、やはり自分が一人上回生のチームで、自分がチームの製作物の下支えをするバックエンドという部分を書いていて、それが上手くいかないとなると、かなり精神的にきついものがありました。
しかも、今回はNode.jsサーバ、ORM, MySQLと使ったことの無い技術がてんこ盛りで、慣例も分からないし、エラーが出ても直感的に解決するなどはできずに、ちゃんとエラーコードを再帰的に読んでいって、問題を一個一個解決していくしかない。 しかもチームにバックエンドを専門的に書いている人がいないため、技術的に相談もできない(だからこそメンターさんにはたくさんお世話になりました。ありがとうございました。ただ、夜の時間帯などは頼るわけにはいかないので結構苦しかったです。。。)。
そうした状況だったので、ストレスとプレッシャーがかなり自分に押しかけていてとてもしんどかったです。2日目の夜はハッカソンから逃げ出したいと何度思ったことか分かりません、というのが正直な感想です。そんな人がチームを引っ張っちゃったものなので、チームメイトには本当に申し訳ないです。やはりハッカソンに参加するには楽しいものにしたいと思っていて、それをこれまでの3回ではちゃんとできていたため、今回準備を怠った自分はしっかりと反省しないといけないなと身に染みて感じます。正直、3回もハッカソンに出てたらうまくいくだろうなどという根拠のない自信を抱いていた自分もいました。ただ、次からはこの反省を生かして、謙虚に入念に準備してそれでも何かしらの挑戦ができるハッカソンにしたいなと思います。
3. 睡眠時間不足
ブラックアウトしそうになった原因の一つとして睡眠時間の不足も挙げられると思います。
今回私は前泊、1日目は6時間しっかりと寝たのですが、そもそも生活リズムが崩壊した前提の6時間睡眠でした。そして出来上がらなかった代償として2日目は十分な睡眠をとることができませんでした。やはり心身ともに健康は大事です。睡眠不足はストレスに直結しますし、そもそも壊れかけの心がに追い打ちをかけるようできつさが増します。分かりきったことですが、
ハッカソンでもしっかりと寝ましょう。
4. 非同期処理の書き方がうまくいかず、断念した箇所があった
1か所だけ非同期で処理を上手く書けなかったところがあり、その部分のせいで一つ機能が作れなかったことがありました。これに関しては完全に私のミスなので、今度練習しておきます。もし非同期処理に関する記事を出していたら褒めてください。
ちなみに、Node.jsサーバでBlobを扱うと、非同期処理のオンパレードになりました。なぜかライブラリ内のいろんな関数が非同期で書かれていて、慣れていないととても扱いに困るのではないかと感じました。Node.jsでBlobを扱うときは要注意です。
ちなみに、BlobとはIT用語辞典によると
BLOBとは、データベースのフィールド定義などで用いられるデータ型の一つで、テキスト(文字列)や整数のように既存のデータ型としては用意されていない任意のバイナリデータを格納するためのもの。
つまり、画像とか音声とかのデータを扱うのにBlobが便利だったりするのです(時と場合によると思いますが)。それで今回は画像をBlobとして扱っていました。ですから、先ほど申した通り、JavaScriptでBlobを扱うとたくさん非同期処理が出てくるので覚悟を決めて?使ってみてください。
5. フロントエンドのレビューができなかった。
今回、コードレビューをする設定はしていたのですが、正直バックエンドでいっぱいいっぱいだった私はフロントのコードレビューがままならない状態でした。
ただ、ちゃんとコードレビューができたとして、フロントに携わっていない人は文法くらいしかチェックできないということにも同時に気づきました。今のままの状態ではフロントエンドがどのようなフォルダ構成で、どのように機能を分けながらコーディングをしているのかが分からないです。逆にそれが簡単に分かるとコードレビューの質がもっと上がるのではないかと考えました。
その解決策の一つとして先にチームで相談しながらディレクトリ構成を考えるということに取り組んでみるのもいいのかなと思いました。
コードを書く人それぞれの思想が分かりますし、チーム内で意思の統率もとれる。しかもハッカソンで作る小規模アプリではディレクトリ構造の把握が簡単なので初学者の理解の向上につながったり、初学者でなくても誰かの思想を受け入れながらコーディングができるいい機会になると思います。ですから、これも準備段階でチームみんなで話し合いながら決めてみるのもハッカソンや、小規模開発においてはいいのではないでしょうか?
6. フロントエンド、バックエンドの区切りを上手く作れなかった。
今回、フロントエンド、バックエンドと分けて実装したものの、言語はTypeScriptと統一していました。
もちろんNode.jsサーバにReactを載せてレンダリングすることも可能でした。ただ、機能を追加するときに二つを分けて実装した方がメンテナンスしやすいのかなと考えたのと、サーバ側、フロントエンド側どちらかで致命的なエラーが出た場合に統合しているよりも分離した方がリスクが分散できると考えたので、今回は二つに分離させることにしました。
話をTypeScriptに戻すのですが、フロントエンド、バックエンドともにTypeScriptで書いている最大の利点は同じ型定義が使えるということです。バックエンド側で作っている型定義をそのままフロントエンドに持っていくと簡単に通信関係の実装ができます。ただ、どうやって型を統一するのかは考慮の余地があります。今回は別のレポジトリを用いてフロントエンドに対してバックエンドのレポジトリからコピーをしていました。その方法だとあまりGitHubを用いているメリットがないので、今回のようにTypeScript統一するならば、フロントエンド、バックエンドどちらも同じレポジトリにして、同一ファイルから型を参照するようにすべきだと思いました。
これまでは今回のハッカソンで上手くいったところです。本当の反省点はこれからで、私がバックエンドを書きながらちょいちょいフロントエンドに関わったりしていました。ただ、それはしない方がいいのではないかと反省しています。
理想のチーム分けとして、フロントエンドとバックエンドが関わるべき個所はエンドポイントのみにする方がいいのではないかと考えています。
なぜかというとフロントエンド、バックエンドが仕事を分けている最大の理由として、フロントエンドはユーザに対して提供するデザインに集中して、バックエンドはそれを支えるデータ処理に集中するという思想があります。そのため、バックエンド側でもっときっちりと区切りを作ってエンドポイントの仕様書を書いたり、フロントに関わらないようにすべきでした。もちろんチームメンバの質問には答えながらという前提条件付きです。
友人が作っているバックエンドではそうしているので、見習います。
7. 準備ほぼゼロの状態で初めてNode.jsサーバを作って失敗した。
私自身、PythonのフレームワークであるFlaskでしか開発をしたことがありませんでした。
ただ今回ハッカソンに出場するにあたって、もっとJavaScriptについて、Node.jsについて知りたいと思い、Node.jsサーバを使いました。それ自体には何の問題もなかったと思います。たくさん悩んだ分、理解が進みました。
ですが、工数を読み違いました。
正確には分からないはずの自分で考えた工数に対して謎の自信を持っていたということです。
サーバ系、インフラ系に強いわけではないので、初めて触る技術に戸惑うことは間違いありませんが、そのことを考慮する力に欠けていました。正直なことをいうと、工数があまりにも未知数なのでハッカソン前にバックエンドの開発を済ましておくべきというレベルでした。Node.js, ORM, MySQLと初めて本格的に触るものが目白押しでしたので工数所見誤りは大反省点です。プロダクトにおいて縁の下の力持ちのバックエンドはものすごく大切ということを肝に銘じておきます。
8. ハッカソンで勝ちたいか、失敗でもいいから技術的に挑戦するか
ハッカソンで勝ちたいか、挑戦するかどちらかに絞る必要はないと思いますが、ただ計画は必要であると強く感じさせられました。
もちろん私自身確実に勝つメソッドがあるわけではないのですが、勝つチームがどんな共通点を持っているか、最低限くらいは把握しているつもりです。そのためそれらの項目が達成できなければある程度勝ち上がることができないとも思います。もちろん、とある技術を使うと決めてその技術の基礎も分からないままにメンターさんにアドバイスをもらい続けるという方法も一手なのかもしれません。
ただ、チームで出場する以上、それをするにもチーム全体でするというのが絶対条件だと思います。
先述した通り、私のように分からない技術に挑戦してチームの足を引っ張ってしまうと、正直作っていて精神的にしんどいです。別のことをすればチームにどんどん貢献することができるのに新しい技術から戻れないところまで来てしまっているから貢献度が落ちてしまう。個人の技術的な成長以外何もいいことがありません。ですから新しいことに挑戦するとしてもリスクマネジメントをしっかりすべきです。簡単にできる代替案やほかの実現方法を考えるべきです。そのような計画を怠るとハッカソンで痛い目に合うかもしれません。
9. いかに使ってみたいと思われるアプリケーションを作るか
最後にこれは反省点というかユーザ向けサービスを作るうえでの永遠の課題であるとは思いますが、作ったものを使いたいと思える人がいるかどうか、自分がプロダクトに愛着を持てるか、もしくは自分がプロダクトのファーストユーザになれるか、とにかくファンがいるプロダクトを作ることが大切なのだなとずっと感じています。
特に今回優勝した作品はアイデア自体はGeo Guesserと近しいものがあり、もしかしたらそれから着想を得たのかもしれませんが、3D空間で実現する没入感のメリットを生かして、写真を撮るというアイデアで私自身つい遊んでみたいと思うものでした。もちろんそのほかの細かい気遣いも素晴らしく、作品の完成度がとても高かったというのもあるとは思いますが、遊んでみたいと思わせるアイデアや工夫がやはり自分のなかで一番大切であると思っています。ですから、まだまだUXに対して知見を増やしていきたいです。
最後に
こうやって振り返ってみると初心者がおかしそうなミスばかりをしてしまったのだなと感じます。油断した隙をハッカソンに突かれたような感じです。ですからもう一度私自身素直に愚直にエンジニアとして頑張っていきたいと思います。長文を最後まで読んでいただきありがとうございました。間違っている点やアドバイスなどをコメント欄に頂ければ幸いです。