プログラミング初心者が2か月弱でハッカソンの最優秀賞を受賞するまで #Next.js - Qiita

始めまして!Limeです!今回、同じ研究室の2人と一緒に開発したアプリ「MATCHAI」が私にとって2回目のハッカソンで最優秀賞を受賞したので、その経験を共有したいと思います!
プログラミング初心者の方が、ハッカソンに出場するきっかけとなれれば幸いです!
ブログを書くのは初めてなので、温かい目で見守ってもらえるとありがたいです!

自己紹介

  • 愛知県出身
  • 工学部情報工学科の3年生
  • 1月末からWeb系のプログラミングの勉強を始める

ハッカソン出場前のスキル

私はもともとWeb系志望ではなくゲーム系を志望していたため、ハッカソン参加前の私のWeb系のスキルは、HTML/CSSの基本的な知識しかありませんでした。
私の知識は、大学の授業で学んだものしかなく、個人開発なども全くしてこなかったため、Gitの使い方やデプロイの仕方も全く知りませんでした。

初めてのハッカソン出場の経緯

こちらは、2回目のハッカソンに出るためのキッカケとなる話なので、賞を取った作品の話だけ聞きたい方は、製作物まで飛ばしてください。

大学2年生も終わり、春休みとなりました。ここまで何もしてこなかったこともあり、就職のために何かしないとか~と考え、サポーターズ様のこちらに参加させていただきました。

お恥ずかしながら、いままで 「ハッカソン」というものを知らず、こちらで初めてそういうイベントがあることを知りました。そして、そこで紹介された以下のイベントに参加することを決めました。

技育CAMPは、「初心者大歓迎」で、製作物の制約もないため、自分でもできると思い参加することを決めました。
参加を決めてから、本格的に勉強をし始めました。

1月末~ハッカソンキックオフ(2/7)まで

とりあえず、基礎的なことはできるようになろうと思い、Progateの5日間だけ無料の有料プランに入ることにしました。

5日間で、HTML,CSS,Ruby,Ruby on Railsのレッスンを終了させました。
HTMLとCSSが想像以上に覚えることが多く、今でも何も見ずに完成させることはできないと思います。
そして、Ruby on Railsですが、初めてのDB操作もあり、MVCモデルにも慣れず、キックオフ前にCRUD操作がギリギリできる、くらいしか習得することが出来ませんでした。

ハッカソン開始~終了まで

今回のハッカソンは、知らない人たちとチームを組んで出場することにしました。
最初の顔合わせの時、テーマ決めと技術選定を行いました。バックエンド側では、RailsとLaravelという案が出て、結果的にLaravelを使うことに決定しました。
そして、次のミーティングまでに開発環境を整えることとなり、開発を本格的にスタートしました。

開発したアプリ「CookKing」

CookKingという、自炊を促進するためのアプリを作成しました。毎日異なる材料が表示されて、作成した料理でバトル!! というコンセプトのアプリです。

トップページ

トップページ

対戦ページ

対戦ページ

私は、ユーザ認証、ミッション、マッチングシステム、レート増減システムを作成しました。RailsでのDB操作がActive Record(Railsにデフォルトで搭載されているORM)であったため、SQL文が書けませんでした泣

一応形にはなっていたのですが、開発中いろいろな問題点がありました。

問題点その1 だれもGitの使い方を知らない

致命的でした。Gitを使わないとチーム開発が出来ません!!ただ、私はゲーム開発の方でSourceTree(Gitを視覚的に扱うことが出来るツール)を使ったことがあったので、全員にレクチャーをして、なんとか開発環境を整えました。ただ、envファイルを手作業で他の人に送信したり、コンフリクトが起きてどうすればいいのか分からなかったり、全然うまくいきませんでした。

問題点その2 フロントとバックエンドの繋ぎ方が分からない

致命的でした。環境構築は他の人がGitを覚えている間に私が勧める手はずだったのですが、非常に苦戦しました。
今となってはInertiaを使っておけばよかったと思っています。当時は何も知りませんでした…

問題点その3 デプロイが分からない

もともとデプロイをやったことがなく、さらに今回はフロントエンドとバックエンドでファイルを分けているため、どのようにデプロイするのが良いのか全く分かりませんでした。
もし今デプロイするなら、ハッカソン時に公開するくらいのものはVercel+LaravelCloudを使うと思います。たぶん。

第1回ハッカソンの結果と感想

結果として、賞を取ることはかないませんでした。テーマはとても面白いと思っていたので、完成しなかったことがとても悔しかったです。

今回のハッカソンの反省点は、私がチームをうまくまとめられなかったこと、環境構築に予想以上の時間をかけてしまったこと、タスク管理を正確にしていなかったことです。

ただ、Webアプリ開発はとても楽しい!! と知り、次にハッカソンに出場する機会があれば絶対に賞を取りたいと思うようになりました!
ここから、第2回ハッカソンのための猛勉強が始まります。

2月末~2回目のハッカソンキックオフ(3/17)まで

勉強した技術は以下の通りです。

  • React
  • Next.js+TypeScript+TailwindCSS
  • Framer-motion
  • Laravel
  • Supabase
  • Git
  • ReactNative
  • Clerk,NextAuth.js

ハッカソンは、個人開発と違い自分だけで技術選定するわけではないため、とりあえずモダンな技術を学んでおこう。と思いNext.jsを学びました。Reactを学んでおけばReactNativeでスマホアプリを開発できるかなぁという浅い理由もこれらを学んだ理由の1つです。

実は前回のハッカソンで、データベースはXAMPPからMySQLを繋いでやっていたのですが、共同開発の時にフロントエンドの人がデータの中身を見ることが出来ず、とても困ったため、クラウドのDBを扱ってみることとしました。

2回目のハッカソン開始~終了まで

出場したハッカソンです。

今回のハッカソンは、同じ研究室の3人で出場しました。このような機会をくださり、本当にありがとうございます。

前回の反省を生かし、今回は次のように進めていきました。

  • 要件を詰め込みすぎない 最初はなるべくシンプルなものにすること
  • 環境構築をすぐ終わらせ、開発時間を多くとること
  • ミーティングをなるべく多くとること(最終日近くは1日1回だった)

結果的に、ミーティングの時間を多くとることが、完成度を高める秘訣だと感じました。要件定義はほんとに大事!

開発したアプリ 「MATCHAI」

今回、私たちのチームは集合をもっと楽にするWebアプリ「MATCHAI」というものを開発しました。待ち合わせ場所に最初についた人がホストとしてルームを立てることで、そのルームに入った人たちはホストの方向に矢印が向き、簡単に合流できる、というアプリです。ほかのアプリとの差別化点は、「共有が楽」「シンプルで誰でもわかりやすいUI」「高度も表示される」という点です。位置情報を使うアプリは無数にありますが、個性を残せたんじゃないかな、と思っています。

トップページ

Top

ホスト側画面

Host

クライアント側画面

Client

使用技術:Next.js + Supabase

前回の反省を生かし、まだ初心者なのにフロントエンドとバックエンドを分けたら混乱すると思い、Next.jsだけになりました。当初は、P2P通信のためnode.jsだったり、以前使ったLaravelを使うことを考えていたのですが、要件の内容から、P2PではなくSupabaseのRealtime機能を使い、難しいバックエンドの処理もないと感じたため、Next.jsだけとなりました。また、デプロイはVercelでしました。リポジトリの登録と環境変数の設定だけでデプロイすることができ、とても感動しました。

アニメーション:Framer Motion

シンプルである代わりに、操作感をよくしたいと思い、Framer-motionを導入しました。Framer-motionはSSR非対応、というデメリットがあったのですが、複雑な機能があるわけでもなく、目に見えて動作が遅くなることもなさそうだったので、導入を決定しました。以下は、ボタンのアニメーションの一例です。

const Info = () => {
  const [showInfoModal, setShowInfoModal] = useState(false);
  
  const openInfoModal = () => {
    setShowInfoModal(true);
    document.body.style.overflow = "hidden";
  };

  const closeInfoModal = () => {
    setShowInfoModal(false);
    document.body.style.overflow = "auto";
  };

  return (
    div>
      {/* 情報アイコン */}
            motion.button
              whileTap={{ scale: 0.8, rotate: 10 }}
              transition={{ type: "spring", stiffness: 400, damping: 15 }}
              onClick={openInfoModal}
              className="absolute top-5 right-5"
            >
              IoIosInformationCircleOutline className="text-5xl text-gray-300" />
            /motion.button>

            {/* 説明モーダル */}
        AnimatePresence>
          {showInfoModal && (
            motion.div
              className="fixed inset-0 backdrop-blur-sm flex items-center justify-center z-50"
              onClick={closeInfoModal}
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
            >
              motion.div
                initial={{ scale: 0.5, opacity: 0 }}
                animate={{ scale: 1, opacity: 1 }}
                exit={{ scale: 0.5, opacity: 0 }}
                className="bg-[#f9f8f7] rounded-3xl p-8 w-80 shadow-lg relative"
                onClick={(e) => e.stopPropagation()}
              >
                motion.button
                  whileTap={{ scale: 0.8 }}
                  transition={{ type: "spring", stiffness: 300, damping: 15 }}
                  onClick={closeInfoModal}
                  className="absolute top-5 right-5"
                >
                  RxCross1 className="text-gray-400 text-xl" />
                /motion.button>

                div className="flex items-center justify-center gap-3 mt-1">
                  Image
                    src="/title.png"
                    alt="MATCHAI"
                    width={200}
                    height={40}
                  />
                  h3
                    className="text-xl"
                    style={{ fontFamily: "NicoMoji", color: "#7d7d7d" }}
                  >
                    とは
                  /h3>
                /div>

                div
                  className="text-gray-600 space-y-4"
                  style={{ fontFamily: "NicoMoji" }}
                >
                  p className="text-lg leading-relaxed">
                    集合を簡単にしたり
                    br />
                    迷子になってもすぐに
                    br />
                    合流するためのアプリです
                  /p>
                  p className="text-lg leading-relaxed">
                    集合場所に着いた人が
                    br />
                    ルームを作成して4桁の
                    br />
                    パスワードを共有します
                  /p>
                  p className="text-lg leading-relaxed">
                    他の人は共有された
                    br />
                    パスワードを入力するだけで
                    br />
                    ホストまで距離と矢印で
                    br />
                    方向が表示されます
                  /p>
                /div>
              /motion.div>
            /motion.div>
          )}
        /AnimatePresence>
    /div>
  )
}

export default Info

気持ちの良い操作感になっているのではないかと思います。

AIを用いた開発について

現代では、AIがとてつもないスピードで発達しています。そこで、新しいプログラミング手法「Vibe Coding」が登場しました。簡単に言えば、アプリケーションの概要をAIに渡し、AIにほとんどの開発をゆだねること、だと私は認識しています。ここでは、初心者がAIに委ねた開発することは良いのか、私の見解を話します。

メリット

1.開発速度が爆上がりする

これは分かりやすいメリットです。CursorやWindsurfなどのAIコードエディタも登場したことで、本当に支持するだけで開発ができます。

2.エラーの修正が速い

これも分かりやすいメリットです。エラー部分をコピペするだけでいいのですから、どうしてエラーが起きているのかわかっていなくても修正できます。

3.完成後のイメージがわきやすい

これは、Vibe Codingというよりは、v0やbolt.newを使っているときなのですが、UIまで作成してくれるため、アプリの構想が付きやすいです。これは非常に大きなメリットです。

デメリット

1.コードが自分で修正できない

今まで自分でコーディングしてきた人は、UIを修正したいときにすぐ修正箇所がわかると思います。ただ、初心者がVibe Codingを用いた開発をすると修正箇所、修正内容を気にしない可能性があり、もしAIがエラーを解決できないとお手上げ状態になってしまいます。

2.勉強にならない

1に通じますが、AIにほとんどすべてを任せる以上、自分の勉強にはならないでしょう。AIのコードを見て勉強すればいいのでは?と思いますが、AIが用いた手法よりも、今回のプロダクトでは効率の良い方法があったりするため、やはり自分で仕組みを理解するのが一番良いでしょう。

新開発手法「創造的破壊」

今回、私がとった開発手法は、新しく考えた手法「創造的破壊」になります。この手法の大まかな開発手順としては、

  • AIに要件を投げて作ってもらう
  • チームで確認
  • できることを確認したら、そのコードを削除
  • 自分で0から作成

となります。初心者は、経験者と違って出来るかどうかもわからない案を出します。そのため、その案がちゃんとできるかをAIに確認してもらって、できることを確認したら自分たちで作成、という流れです。

メリット

1.方針が立てやすい

AIが最初に作ってくれるおかげで、必要なAPI、処理、ボタンなどがわかります。初心者プログラマーにとって、向かうべきゴールがわかることはとても助かります。

2. 勉強になる

この手法では、必要なライブラリなどは参考にしますが、実行処理は参考にしませんでした。そのため、全部調べることとなり、非常に勉強になりました。

デメリット

1. 時間がかかる

この手法には重大なデメリットがあります。Vibe Coding→自分で開発とするので、とても時間がかかります。ただ、向かうべきゴールが見えていることから、精神的負担は編ているように感じます。

非常にデメリットが痛く、賛否あると思いますが、初心者がAI便りの開発をするくらいなら、こちらのほうが勉強になるかと考えます。
以上、新手法の提案でした。

今回の開発の反省点

1.要件定義があいまいだった

前の項で要件定義の大事さを唱えましたが、それが大事だと気付いたのはハッカソン終盤でした。やはり、プロダクトは実際に使ってみないと何が足りていないのかわからないので、早めにいろいろな人にテストさせてみることが大事だと思いました。
発表当日に「アプリ内にチャット機能があると嬉しい」という要望を受けて、前日の夜からチャット機能の開発に取り組んだのですが、結果的に終わったのが当日の朝でした。
何度も言いますが、要件定義は本当に大事です。ほんとに。

2.要件定義にデザインの概要を含んでいなかった

これまた要件定義のお話です。今回デザインを、デザイン担当の方に任せっぱなしにしていました。
そして今回のプロダクトでは、高度が表示されることから、Three.jsを用いた青色の3D矢印を作成しました。
ただ、上の写真を見てわかるとおり、デザインに合っていなかったため、没としました。
これも、デザインの概要(シンプル?近未来的?)を決めておけば、起きなかったことかと思います。

3.DBのRLSが全くわからなかった

RLSとは、(Row-level security)の略で、DB操作にアクセス制限をかけることができるシステムです。例えば、同じルーム内の人の位置情報しか取得できない…..のような制限をかけることができます。
ハッカソンで提出するくらいならそこまで考えなくても…と思うかもしれませんが、位置情報を取得してDBに保存している以上、私はこれに開発初期から頭を悩ませていました。今でも全く理解できていません。
RLSをかけるとデータが取得できずにエラーとなってしまっていました。結局、このハッカソンの期間内に解決することはできませんでした。どれもこれもSQL操作をSupabaseのGUIに頼り、勉強しなかった結果です。最近はSupabase Cliを使ってRLSを設定しているため、この時よりは理解できているのではないかと思います。

第2回ハッカソンの結果と感想

結果として、このプロダクトで最優秀賞企業賞(TeckTrain様) を頂くことができました!
バックエンド側をやった身としては、要件的にはとても簡単だと感じていたので、これをプレゼンや、デザインで最優秀賞まで引っ張ってくれたチームの2人には頭が上がりません。本当にありがとうございます。

前回と比べてテストや新規機能の追加など、時間を多くとれたこと、チームが知り合い3人で、最初からコミュニケーションがとりやすい環境であったこと等が賞を獲得できた要因だと思いました。いいプロダクトを作るには、複雑で大規模なアプリケーションを完成させることも重要ですが、何より 「普段使いできること」「アイデアが今までにないこと」 を満たすことで、心を惹きつけることが大事だと思います。

まとめ

プログラミングで成長するために一番大事なのは、圧力がかけられる環境でのアウトプットだと感じました!初心者の方は、技術がないとは思わずにハッカソンに出てみれば、一気に成長できると思います!おすすめです!!

そして、すごいエンジニアになるには単に技術力を上げればいい、というわけではなく、「チームをまとめる力」「テーマを考える力」「プレゼン力」などいろいろな技術が必要ということも分かりました。これらは、個人開発をしているだけでは培われない、ということも。

また、基礎的なネットワークの理解をすっ飛ばしてきているため、これから個人開発もしながら、インターンや書籍等で起訴を含めスキルアップしていこうと考えています!

最後に、今回開発した「MATCHIAI」のソースコードはGitHubで公開していますので、興味のある方はぜひご覧ください!

GitHub: LimeIvy/MATCHAI

実際のサイトはこちらからアクセスできます
※テスト用にデプロイしたものです!閉鎖しているかもしれません!
https://matchai-next.vercel.app/



フラッグシティパートナーズ海外不動産投資セミナー 【DMM FX】入金

Source link