本記事は12/04 ~ 12/12 にかけて行われた部内でのハッカソンについての記事です。
メンバー
サーバー
- logica
- xxarupakaxx
クライアント
- reyu
- Rozelin
デザイン
- annin
制作物
アイデアをヒキダシ
ツナいで
ヘヤで共有する
構造化されたアイデアの可視化をサポートし、アイデアと記憶を引き出すブレインストーミングアプリ、それが
「ヒキダス」と読みます。"K"じゃなくて"Q"なのは、traP内で使われているメッセージングアプリ、traQにあやかって。
概要
このように、「ヘヤ」と呼ばれる共同編集スペースに仲間と一緒に入ります。
「ヒキダシ」と呼ばれるコンポーネント単位でアイデアを一つ一つ括り、それを自動的に親子関係で繋いでいきます。下図のような木構造でアイデアをまとめることができます。
さらに、ヒキダシには文章の同時編集が可能な説明欄がついていたり、色も自由に変えられたりと、あなたのアイデアを整頓するための機能が盛りだくさんです。
ソースコード
- サーバー: https://github.com/hackathon-21winter-05/HiQidas
- クライアント: https://github.com/hackathon-21winter-05/HiQidas_UI
使用技術 (特に重要だったもの)
Protocol Buffers
Googleによって開発された、スキーマ定義言語とそれによって定義されたスキーマをバイナリにしてくれる技術です。
今回クライアント - サーバー間の通信(REST APIとWebSocket)において、エラーメッセージ以外の部分は全てこのProtocol Buffersでエンコードしたバイナリデータを送りあっていました。
gRPCという通信規格の急成長とともに普及してきている...らしい。
- 得られたメリット
複数人の開発でも、おかしなスキーマが送られることがないので安全。
Open APIのYAML書くよりは断然楽でした。 - 大変だったところ
未使用の技術だったので練習を要しました。
Protocできちんとビルドできる環境を整えるのが結構大変で、Goは比較的すんなり行けましたが、ブラウザ上のJavaScript向けにビルドするための方法は破綻するたびに変えていたので、計3個ほど試すことになりました。
yjs
Google DocsやHackMDのようなリアルタイム同時編集が欲しいという話になり、yjs というフレームワークを使おうと考えました。これはCRDTというデータ構造 (を改良したもの?) を実装していて、Web上で動くテキストエディタとのバインディングも用意されているため低コストで導入できると考えました。
これによってクライアント間の同期は互いに更新データを送り合うだけで簡単に実装できたのですが、Go製のサーバーでその更新データをどう永続化するかが問題になりました。yjsの更新を適用する操作をGoで再実装するのが一番よかったのですが、開発期間の短さもあってあまり現実的ではありませんでした。
最終的には別でNode.jsを動かしてそこで更新データの適用を行い、その結果をDBに保存するようにしました。
事前準備
企画 / 構想
テーマ「Draw」から連想されるものや、考えられる制作物をメンバーそれぞれが2つづつほど考え、それらを統合する形で制作物を決定しました。最終的に「記憶・アイデアの引き出し(Drawer)」という形で、ブレインストーミングの補助 / 構造化メモツールのようなものを作るという事で合意しました。
ハッカソン開始直前には、どのような機能を実装するのかすり合わせを行い、大まかな仕様と取り組む優先順位を決めておきました。
デザイン
実際に作り出すのはハッカソン期間が始まってからというルールだったので頭の中でなんとなくこういう感じにしようというイメージを固めていました。
サーバー
使用する技術スタックを二人(+ ほかの班員)で話し合って決めました。
認証はtraQ OAuthを選択。
サーバー - クライアント間の通信手段は
- REST API + WebSocket with JSON
- REST API + WebSocket with Protocol Buffers
- gRPC
の3つの候補を出し、議論の上で「REST API + WebSocket with Protocol Buffers」という技術スタックを選択しました。
データの永続化はGormを使ったRDBでの管理を選択。
traQ OAuth、Protocol BuffersとWebSocketに関してはどちらも触ったことのない技術だったので練習が必要だと思い、最低限の機能しか持たないメッセージングアプリケーションを作って練習を積みました。WebSocket / Protobufに関しては先輩3人の作品、Emoineが非常に参考になりました。
アーキテクチャ・Protobuf・WebSocketの勉強を積み、頭の中で実際の実装における処理・依存の流れをある程度設計しておきました。
クライアント
担当者2人の経験などからVue3 + TypeScript + Sass を使用することなどが決まりました。
それ以外については特には決めず、必要に応じて考えようという感じでした。
ハッカソン期間 (12/4~11)
サーバー
- ハッカソンが始まってすぐさま、traPで開発しているPaaSのShowcaseにデプロイできるようにCI / CD環境を整えました。
- WebSocketがヘビーな実装だったため、REST APIの実装をxxarupakaxx、WebSocketをlogicaが担当することにし、各々で実装を進めていきました。
- 最初からクリーンなアーキクチャで書いていたため、コンフリクトも起こらず依存関係がわかりやすいものになっており、非常に実装が進めやすかったです。
クライアント
- 最初のうちは各自進めていましたが、途中からは @Rozelin がヘヤ一覧やログインページ、@reyu がヘヤのページを主に担当するようになりました。
- サーバーと実際に繋いで動作確認するのが最終日になってしまい心配でしたが、比較的スムーズに進んで安心しました。
デザイン
- Figmaを用いて初めの1~2日で構想を形にしていきました。書き起こす段階で何個か設計破綻している部分があったりしたのでヒヤヒヤしてました。
- 後半はクライアントの実装を確認してcss部分の修正をしたり、お願いしたりしました。
- 最終日にロゴ等々を制作しました。
開発日記 (クリックで展開)
一日目 (12/4)
logica
- DBスキーマとAPIエンドポイントをMDで設計し、arupakaに実装を任せた
- アーキテクチャの構想を練った。クリーンアーキテクチャに寄せた
- CI環境を整え、CD環境と開発環境作りに手を出し始めた
xxarupakaxx
- dbのモデルを書きかきした
- エンドポイントをプロトコルバッファで生成しようと試みた
annin
- 想定では一日目でワイヤーフレームを完成させるつもりだった
- なんとなくそんな感じがしていたが、実際に作ってみると考えなければいけない部分や破綻しかねない部分がでてきたので頭を悩ませていた
- 日付が変わってしまったので広義一日目のうちに終わらせることを決意
reyu
- プロジェクトの環境構築などをしつつ様子見をしていた
- @reyuの睡眠時間の崩壊により連携があまりとれず
Rozelin
- 何しようってなったのでプロジェクトの初期設定をした
- 必要そうなページを洗い出してissueだてとページのpathを考えたりした
二日目 (12/5)
logica
- デザインのフィードバックをめっちゃした
- 開発環境を整備した (DevContainerとホットリロード環境)
- 通話であるぱかと開発イメージの共有を行った。アーキテクチャを中心に、あるぱかが見通し立ってなさそうなところを重点的に補完していった
- エンティティモデルと通信のスキーマに俺がこだわりを持ちすぎて、あるぱかを無限レビュー編に入らせてしまった
xxarupakaxx
- restAPIのエンドポイントをプロトコルバッファで書いた
- logicaのアーキテクチャ、ws等の説明が非常にわかりやすかった
annin
- 明け方くらいにいい感じにデザインがまとまった
- フィードバック受けつつ修正、追加、整理等々。。。
reyu
- プロジェクトの環境がだいたいいい感じになった
- 共同編集について調べた
- 睡眠時間を改善しようとした結果夜9時の集会を寝過ごした
Rozelin
- デザインが決まった部分からcssをこねこねしてた
- その他必要そうなライブラリをインストール
三日目 (12/6)
logica
- フロントエンドにNodeのv16を勧めた
- CD環境を完璧に整えた
- ヘヤの仕様を詰めた
- Repositoryのインターフェースを用意し、実装をあるぱかに頼んだ
xxarupakaxx
- Protocol Buffersって柔軟すぎるなぁと思った今日この頃
- cleanなアーキテクチャで実装
annin
- 大体デザインが終わる
- コンポーネント整理しつつ設計に不備がないかチェックしてた
- 仕様の部分で齟齬が合ったのですり合わせをおこなう
reyu
- 共同編集がやばそう
Rozelin
- 時代に取り残されてnode-v14を使っていたのでv16にアップデート
- ひたすらcssをこねこねする
- †css完全理解†する日も近いはず()
四日目 (12/7)
logica
- OAuthのハンドラを整備した
- WebSocketストリーマーの基礎の部分を作った
- あるぱかに今回目指すRepository層の実装の形について詳しく説明した
xxarupakaxx
- レポジトリを実装していた
- pixivの方々と会話をした
- アーキテクチャについて質問したが予想以上に回答が返ってきて驚いた
- 結局は同じものを何回も作って自分のベストプラクティスを見つけるのが良い
- よく言われるのが同じものを3回作ってみるだそう
- 既存のアーキテクチャにこだわらず、自分だったらどのように依存考えるかを考えて何度もトライすればよい!!!!!!!!!!!!!
annin
- ロゴ考えてた
reyu
- 共同編集がやばい
- 丸2日間クライアントを@Rozelinに丸投げしていることに気づく
Rozelin
- やっぱりcssこねこねしてた
五日目(12/8)
logica
- reyuくんが「共同編集のためにYjsというライブラリを使いたい」と言ってきた
- 調べてみると、今まで考えていた構造の中に新しいWebSocketの受け口を作らなければいけなかったり、Goでパースはだいぶ無理があるのでNode.jsを使ったパーサーを追加で実装しなければならないとわかった
- 勘違いもあってちょっとreyuくんともめかけた
- 最終的にお互いに考えを言い合って、使うことで合意した (= 仕事は増えた)
- YjsのためのWebSocketの受け口とパーサーの実装方法を検討した
/users
のエンドポイント群の実装に着手した- 全てのアーキテクチャ層の基本設計が揃い、完成の形が見えてきた
xxarupakaxx
- レポジトリの修正だけしてた <- これしかしてないのでは:thinking::guaaa:
annin
- ログインページ考えてた
reyu
- 共同編集はある程度目処が見えてきた
- さすがにクライアント投げすぎなので自分もCSSこねないとな~となる
Rozelin
- 相変わらずcssこねこね
- 共同編集なんも考えてなかった
- apiを叩く部分以外のトップページがほぼ完成
六日目 (12/9)
logica
- ルーターパッケージの大改修を行った
- ハンドラを次々実装していった
xxarupakaxx
- heyaのエンドポイントを実装した
annin
- クライアントの実装にあたって説明が足りない部分などを補足したりした
reyu
- クライアントやばくね?と気づく
- CSSと対話した
Rozelin
- cssこねこねは終わったけどロジック周りの実装で盛大にバグらせる
- サーバーとの通信周りを@reyuに丸投げしていることに気づく
七日目 (12/10)
logica
- REST APIのハンドラをあるぱかに丸投げした
- WebSocketのハンドラを実装していた
- 名前の統一が難しくなってきた
xxarupakaxx
- heyaの実装PRが81になっていた
- heya以外にもwireを通したり、Lintを通したり...
- wireってきもちいいいいいいと思いました
annin
- 進んできたクライアントの実装を確認して、修正したりお願いしたりした
reyu
- ヘヤの機能を実装していた
- いくつかの機能については見なかったことにした
- 自分の書いたコードが技術的負債になっていてつらい
Rozelin
- ようやくapi叩く部分を書き始める
- 保守性低そうだなと思いつつ時間がないので書きやすさをとる
八日目(12/11)
logica
- WebSocketのハンドラをとりあえず書き終えた
- クライアントにテストしてもらってバグ修正をしまくった
- ユーザー認証の部分を実装した
xxarupakaxx
- favoriteに関するエンドポイントを実装した
- User以下のエンドポイントを実装した
- デバッグをしてバグを見つけていたりしていた
annin
- 引き伸ばしてたロゴを完成させた
reyu
- クライアントとサーバーを繋いだ
Rozelin
- 実績解除: 本番環境破壊
ちょっと延長戦 (12/12の夜中)
logica
- Nodeを使ってYjsのパーサーを書いた
- これで説明が保存されるようになるはずだった
- パーサー、ブラウザ環境が必須のライブラリを使用していた都合上Node上では動かず、絶望の淵で眠りについた
- 結局起きてからYjsのドキュメントをしっかり読んで、無理にYjsでエンコードされたバイナリを文字列にするんじゃなくて、バイナリのまま出力して保存すればいいことに気が付いた
結果
発表はlogicaが担当しました。
残念ながらどの賞も受賞することはできませんでしたが、今回のハッカソンに実動部隊として協力して下さったピクシブの社員様方の中で、2人が好印象を示して下さいました。
traPの中ではやはりゲームに票数が集まったみたいなので、今回の構想は社会人向けのアプリとしての方がウケが良かったかもしれませんね。
感想
logica
- Webアプリのサーバーサイドを0から組んだのは初めての経験だったので、苦労することも多かったが何とか形にはなったので一安心。
- 勝手にやってた事前練習がだいぶ役に立ったのでとても嬉しい。
- とても楽しかったし、良い勉強になった。
- 開発は継続するので、目標決めて頑張っていきたい。
xxarupakaxx
- pixiv賞、および最優秀賞には選ばれなかったが発表会後のPixivの社員さんとの雑談でnorioさん賞とuzimaruさん賞をいただきました
- ハッカソン楽しかった
- pixivの方々との雑談は楽しかったし質問も回答がたくさん来てうれしかった
annin
- 丸々一つのコンテンツの設計をやらせてもらうという贅沢な経験をさせてもらいました。
- なるべくクライアント側の実装負担が抑えられるようなデザインを作る、という目標を立てていたのですが、あんまり達成できず。。。
- 私の難しい要望・要求を通してくれた強強エンジニアのチームメンバーに感謝です。
reyu
- 共同編集が色々と辛かった
- 発表には間に合わなかったものの最終的には動いたので、よかった
Rozelin
- 終了直前にバグが結構見つかってヒヤッとしたものの、何とか形になってよかった
- 賞は逃したもののピクシブの方から高評価を頂けたのは嬉しかった
今後の展望
今回の作品はまだまだプロトタイプなので、今後も開発を続けきちんとtraP向け・外部向けにリリースする予定です!
サーバーサイドはサーバー - クライアント間通信をgRPCに移行してみたいという思いがあったりなかったり...?
最後に
是非2021冬ハッカソンに参加した他の班の開発ブログも覗いてみて下さいね!