# P2HACK2023の記事(副題: ハッカソンを襲った技術的負債をなんとかした話) :::info 言いたいこと書いただけです ::: :::info 本記事は[あらた界隈とそのまわりとそのまわりとそのまわり 訳: だれでも参加可能 なアドカレ 2023 ドキッ!?オタクだらけのアドベントカレンダー(完走するとは言っていない)](https://adventar.org/calendars/9714)の12日目の記事(遅刻)でもあります。 ::: 私たち「SEXY♡DYNAMITE」は、P2HACKS2023 Post-PBL部門に参加し、最優秀賞を勝ち取りました。本稿では、私たちが今回のプロダクトで使用した技術を紹介します。 技術的な面以外に関しては Sによる: P2HACKS2022からP2HACKS2023へ https://hackmd.io/@sumeshi96/r1loWK2UT Pによる: P2HACKS2023最優秀賞をいただいた話 https://note.com/pranarinasu/n/ne66e501005ec をご覧ください。 TL;DR - ハッカソン開発中盤にフレームワークを変えた - リプレースにより開発速度が向上した - 技術的負債はハッカソンの規模でも早めに解消すべき - そもそもハッカソンでは使い慣れた技術を使うべき ## プロダクトの概観 本プロダクトは、身も蓋もない言い方をすると「電子マネー残高が減ったことを確認したときに、懐に入れたファンが外気を取り込み、物理的に懐が寒い状況を作り出す」プロダクトでした。このことから、少なくとも「電子マネー残高を確認する機能」「残高が減ったことを確認できたときにファンを自動でオンにする機能」が必要なことがわかります。電子マネー残高に関しては、当初PayPayをスクレイピングすることにより確認することを想定していましたが、利用規約の精査をしている時間がないこと、また運営会社に対する問い合わせをしている時間がなかったことを踏まえて避けました。その結果、より広く受け入れられているであろうSuica互換交通系ICに対するNFCによる残高の読み取りという着地点となりました。ファンを自動でオンにする機能に関しては、sumeshi君がRaspberry Pi Zero WHを持っていたのでそれを使いました。 ## 技術スタック これを踏まえた最終的な技術スタックが以下の図になります。 ![image](https://hackmd.io/_uploads/B1qqbulDp.png) (発表資料より引用) この図を見て意外に思われた方もいらっしゃるかと思いますが、本アプリケーションのフロントエンドでは古き良きApache Cordovaを利用しています(実際、審査委員長に突っ込まれたポイントでした)。実は、開発当初は以下のような技術スタックで開発していました。 ![firebase](https://hackmd.io/_uploads/Byq0XuxP6.png) (3分で作った) はい、全く別物ですね。当初、私はネイティブアプリをスマートフォン向けに開発した経験がほとんどなく、無難なスタックを選択した結果がこうでした。しかし、この技術スタックには複数の避けられない問題がありました。 ## 旧構成で発生した問題 ### React Native まず、React Nativeでは以下の問題が発生しました。 1. OSの機能をガン無視したUIを作りづらい 当初、私はデザイナーZによるワイヤフレームに従って作業を行っていました。その段階では問題なかったのですが、後から上がってきたデザインを見るとNeumorphismによるとても優雅なものになっていました。React Nativeを含むネイティブのUIフレームワークでは端末のオペレーションシステムに従ったデザインはとても作りやすいのですが、それを外れるとスタイリングの幅がHTMLより狭いため難しくなってきます。Neumorphism UIライブラリを使用する方法も試しましたが、レイアウトの都合上アーティファクトが発生してしまうなどの問題が発生したためあきらめました。 2. Expoを採用するとビルド基盤がロックインされる React Nativeの公式ページではExpoフレームワークを使用する方法が案内されていますが、これは罠です。Expoではアプリケーションのビルドにマネージドのクラウドサービスを利用する必要があります。これを回避してローカルでビルドすることもできますが、当時使用していた開発機であるWindowsではビルドできないことが判明しました。件のクラウドサービスでは数回までは無料でビルドできるそうですが、それ以降はビルドごとに料金が発生するとあり素早いイテレーションに影響することがわかりました。(もちろん、SEXY♡DYNAMITEにそんなかねはありません) ### Firebase また、Firebaseでは以下の問題が発生しました。 1. リアルタイムのイベントが表現しにくい Firebaseは、基本的なメンタルモデルとしてモバイルから直接データベースを読み書きすることを前提としています。そのため、今回のように外部のシステムに一回限りのイベントを発生させるなどの処理は書きづらい面がありました。一応実装はできましたがいつバグが発生するかわからないような書き方になってしまいとてもつらかったです。 2. Firebaseの認証設定でトラブルが発生して詰んだ Firebaseではデフォルト機能として(むしろ筆頭機能として?)認証が提供されていますが、Firebaseのフレームワークにそれをすべて移譲することになるため、フレームワーク内で何か問題が発生したときにそれをデバッグすることが非常に困難になります。特に、私はFirebaseにもReact Nativeにもネイティブアプリケーションにも詳しくなかったため、トラブルが発生したときに問題の解消を図ることができませんでした。実際に発生した事象としてはアプリケーションをapkに固めた時に認証ができなくなる問題が発生しました。最終的にこれは匿名ログインを使うことにより回避したのですが、このトラブルが発生した時点で相当頭に来ていました。 ## リプレース さて、これらの問題に直面したのち、私は…逃げました。 わたしの悪い癖なのですが、構造上からくる困難が発生するとすべてを破壊してから1から作り直したくなるというのがあります。その悪癖が今回も発動し、ハッカソンの後半戦が始まった6日目にフロントエンドのフレームワークを1から作り直すという決断をしました。 ![キャプチャ](https://hackmd.io/_uploads/H1Zehvxwa.png) ![キャプチャ2](https://hackmd.io/_uploads/SyNl3vePT.png) ここで、読者の皆さんはApache Cordovaに関してあまり詳しくないので、軽く説明しようと思います。このフレームワークは平たく言うと枠のないブラウザからネイティブ機能を呼び出せるようにしたもので、最近で言うとElectronやTauriに似た機能を持つハイブリットアプリケーション用のフレームワークになります。React NativeがネイティブのUIシステムを使用するのに対し、これらのフレームワークはただのブラウザであるためHTMLとCSSを使って画面を構成することになります。私はWebフロントエンドエンジニアなので、このリプレースを通してHTMLとCSSによる表現力を利用することによりデザインの再現度を高めることができました。 また、今回の構成ではApache Cordova上でViteを使用しています。この構成では通常静的アセットがCordovaのストレージに焼きこまれてしまうためViteのHMRを利用することはできませんが、CordovaのWebviewでの外部ページへの遷移を許可することにより普通のWeb開発と同じようにHMRを利用することができるようになります。 これでデザイン上の問題は回避することができましたが、Firebaseによる制約は依然残ったままでした。そこで、バックエンドを新たに作成することによりこの問題を解消することにしました。通常バックエンド技術のリプレースは大きな工数を要しますが、幸い今回のプロダクトではアーキテクチャとしてFlyweight DDDおよびクリーンアーキテクチャを採用していたためデータベース部分の組み換えと情報の取得(クエリ)を少々変更するだけで移行が完了しました。 このFlyweight DDDというのは、CQS(コマンド・クエリ分離原則)にのっとったうえでコマンド部分をドメインオブジェクト中心にかっちりと書き、クエリの部分ではフレームワークに依存した書き方をすることで開発速度とロジックの整理を両立するアーキテクチャです。Firebaseではサブスクライブ機能などのデータ取得に便利な機能が搭載されていたためこれを生かすために採用していたものでした。また、クリーンアーキテクチャはコマンド部分でドメインオブジェクトにデータベースの知識が入り込まないように利用しました。 リプレースが完了したのはコードフリーズ72時間前くらいでしたが、スタイリングは簡単にできるようになり、バグの心配も減ったため開発速度は向上しました。 ## 結論 失敗した面として、今回のハッカソンでは開発中盤にバックエンド・フロントエンド両方のフレームワークを変更することになってしまいました。これは最初にしっかりと技術検証をしていれば避けることができた事態だと考えています。React Nativeでネイティブの見た目のUIを逸脱するとスタイリングの難易度が上がることはすぐにわかりますが、そのようなことを考えずにとりあえず作ることの危険性を痛感しました。 また、成功した面ではリプレースによるリファクタリングを行うことにより安心して作業をすることができるようになりました。正直Firebaseは技術的負債になると最初から考えていましたが、ハッカソン期間でそれが問題になるとは思っていませんでした。その技術的負債を早期に返済しプロダクトを完成させることができたのはアーキテクチャの勝利に他ならないと考えています。つまり、ハッカソンでもできる範囲で技術選定と設計をちゃんとしておこう、ということです。ありきたりな結論ですが、やはりそれが重要なのだと思います。 ## チームとハッカソン全体について SEXY♡DYNAMITEは非常に優秀なチームで、私は本ハッカソンで技術以外の一切をチームメンバーに丸投げしていました。これにより、私はプロダクトの実装に集中し、様々な技術が絡む複雑なプロダクトをを完成させることができました。勝ち取った最優秀賞はすべてのチームメンバーが最大の能力を発揮することができた証拠だと思います。 このチームメンバーを集め、それぞれが個のポテンシャルを最大限発揮できるようにしたストラテジックプロダクトマネージャS、すばらしいデザインを提供し、様々な無茶ぶりに対応してくれたデジタルユーザージャーニーエキスパートZ、プロダクトの魅力を引き出すプロモーションビデオを制作してくれたマルチメディアオーサリングディレクターP、そしてハッカソンという場を与えてくださったP2HACK2023の運営の方々への感謝は尽きません。 とりとめのない文章になってしまいましたが、言いたいことは言ったのでこの記事はここまでです。ここまで読んでくださりありがとうございました。