メンバー
フロントエンド: @cp20 (23B), @zoi_dayo (24B), @Alietty (24B)
バックエンド: @ikura-hamu (22B), @tidus (24B)
作ったもの
今回のハッカソンのテーマ「さい」「えん」「す」の「えん」から、絶対に炎上する新世代SNS「発火村」(はっかむら)を作りました!
結果は最優秀賞でした!🎉🎉🎉🎉🎉🎉
サービス自体は部内限定公開なのですが、リポジトリは一般公開されています。
https://github.com/traP-jp/hakka-mura
できること
XのようなSNSですが、投稿されたすべての文章が、GPT-4oによって炎上しそうな文章に変換されます。
投稿に対してリアクションを付けることもできます。
マウスホバーすると元の文章を確認できます。
「ハッカソン楽しい」という平和なメッセージが、いかにも炎上しそうなメッセージに変換されてしまいました。このブログのタイトルも『2024年 春ハッカソン 24班 「発火村」 ブログ タイトル』を投稿した結果です。
他には下のような機能があります。
- トレンド
- 一定期間内でリアクションが多い投稿の一覧を見られる
- ユーザーページ
- ユーザーの投稿一覧や、ユーザーのリアクション数を確認できる
- traQ投稿機能
- 発火村のUIから、traQにメッセージを共有できる
技術
フロントエンドとバックエンドを同じ1つのリポジトリで管理するMonorepo構成で開発しました。
https://github.com/traP-jp/hakka-mura
フロントエンド
VueとViteを使ったCSR (Client-Side Rendering) の構成です。特にNuxtなどのフルスタックフレームワークは使わず、シンプルな構成にしました。ただ複数の画面は用意したかったのでVue Routerを使ったルーティングを行いました。さらにESLintとPrettierを使って静的検査とフォーマットを行いました。
ただ頑張って環境を作ったわけではなく、npm create vue
コマンドでオプションをぽちぽちしているだけで先のような環境を簡単に作ることができます。あまりにも神過ぎる。
せっかく静的検査をしているのでGitHub Actionsで毎push時にLint + Format(check) + Type Checkを行うように設定しました。ただフォーマットがVSCodeの設定と npm run format
したときの設定の違いに苦しめられていました。解決策は分かっていません。
普段個人開発するときは開発する過程でデザインを決めて行くことが多いのですが、今回は事前にFigmaでデザインを作っておいてそれをメンバーで共有しながら実装していく方針でやりました。先にカラーパレットとかを作っておくことで統一感のある配色ができたりとか、実装がキレイになったりとかでメリットはそれなりにあったと思います。
Figmaのデザインの一部
事前に決めておいたカラーパレット
バックエンド
GoとMariaDBです。HTTPサーバーのフレームワークはlabstack/echo、DBへのアクセスはjmoiron/sqlxを使っています。新入生向けに、traPのWebエンジニアになろう講習会と同じ構成にしました。
パッケージ構成は、短時間で開発できるようシンプルにしつつ、パッケージができるだけ疎結合になるようにしました。
普段、ハッカソンのような短期間の開発では下のようなディレクトリ構成にしていました。
.
├── main.go
├── handler # HTTPハンドラーを実装し、repositoryのinterfaceを使う
│ ├── post.go
│ └── reaction.go
└── repository
├── post.go # DB操作のinterfaceを定義する
├── reaction.go
└── impl
├── post.go # 親ディレクトリで定義されたinterfaceを満たすように実装する
└── reaction.go
repositoryパッケージにDB操作のinterfaceを定義し、その下のディレクトリにその実装を書いています。
しかし、Go Code Review Commentsのinterfacesの章 には以下のように書かれています。
Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values.
(Goのインターフェースは一般的には、interface型の値を実装するパッケージではなく、これらを使うパッケージに属します。)
これに従えば、DB操作のinterfaceを使うのはhandlerパッケージなので、repositoryのinterface定義をhandlerパッケージに置き、それをrepositoryパッケージで実装すべきです。
今回はこの方針で実装しました。
.
├── main.go
├── handler # HTTPハンドラーを実装する + repositoryのinterfaceを定義する
│ ├── post.go
│ └── reaction.go
└── repository
├── post.go # interfaceを実装する
└── reaction.go
使う側にinterface定義を置いておくと、コードを書くときに見やすかったです。
しかし、エラーハンドリングに困りました。handlerでrepositoryから返ってきたエラーの種類に応じて処理を変えたいとき、どこでそのエラーを定義すればいいか困りました。ハッカソン後に部内で質問した結果、2パッケージに分けるのは無理があり、repositoryのinterface定義を行うためのパッケージが必要で、エラーはそこに定義すべきという結論になりました。他に良い案がある方は教えてください。
感想
Alietty
自分はチーム開発もWeb開発も未経験で、Vueなどの知識も基礎的なものしかなくはじめは置いてけぼりにされないか不安でした。しかしチームの皆がわからない部分を教えてくれたり、エラーの解決を助けてくれたりしたおかげで、自分のできる範囲で開発に参加することができました。二日間貴重な経験ができて楽しかったです。チームの皆ありがとう!!(次のハッカソンまでにもっと技術を身につけてリベンジしたい...!)
cp20
今回初めてGoとのMonorepo構成を触ったんですが、わりかし開発体験が良くてよかったです。ハッカソンなのでバックエンドのAPIを作るのと並行してフロントエンドの画面を作っていく必要があるのですが、最終的なAPIの繋ぎこみをAPIができているところからやっていっていました。そのときに特にリポジトリの切り替えをせずとも git pull
するだけで変更が反映される (しかもバックエンドの再起動なしで) のはかなり楽でした。
いくらはむさんが出してくれた最強アイデアによって最優秀賞をもらってしまったので、いくらはむさんに感謝しながら賞品の焼肉を食べようと思います。もちろんいくらはむさん以外のチームメンバーもめちゃめちゃ実装頑張ってくれて超助かってました。感謝。
ikura-hamu
ふざけたものを作れて楽しかったです。ふざけたものなのにcpくんが作ったデザインがかっこよくて余計に面白かったです。24Bの3人は全員やる気も能力もすごい高くて、一緒に開発して楽しかったです。
一応リーダーだったはずですが、あまりリーダーっぽいことはせず、わいわい開発できました。traPのイベントの中でハッカソンが一番好きだなと再認識しました。
tidus
チームで開発するのは初めてで正直かなり不安でしたが、チームの皆さんと楽しく開発することができてよかったです。Go言語でバックエンドを作るのも初めてだったのですが、分からない部分は教えていただいたりしながら開発を進められたし、リリース直後にトレンド機能が落ちてしまった際の対応も体験できたのでとてもいい経験になったと思います。ありがとうございました!!
(ちなみに、この不具合の原因は僕の書いたコードです、ごめんなさい!!)
zoi_dayo
コンポーネントをちょこちょこ作ったり、issueを生やして消化したりする仕事をしてまいた。チーム開発も、バックエンドがあるサイトの開発も初めてだったので不安でしたが、気づいたらめっちゃすごい案とデザインができていて、作っていてとても楽しかったです。二日目の午後にちょっと手が空いたバック班が試験的に使ってみて爆笑してるのが印象的でした。作ったページを色んな人に評価してもらえるの、めちゃくちゃ嬉しかったです!
チームメンバーの皆さん、2日間ありがとうございました!!!!!