こんにちは。WhatACottonといいます。わたこっとんです。
この記事では1年かけて開発してきたカリスワークスについて書いていきたいと思います。
# このプロジェクトの経緯
大学に入学してから、何か頑張りたいと思って題材を探していたところ、母親から「そのうちブレスレットを売ってみたいんだよね。」という話を受け、〇〇カリや〇〇マなどで出品するのもいいけど、システムを1から開発してみるのも面白そうだよねという話になり、そこからプロジェクトは始まりました。1から勉強して、全てやってみたいという思いから後述する書き直しまでは友人達に相談することはありましたが、全て一人で実装を行ってきました。
ちなみにこのプロジェクトは通年で個人がやりたいテーマを決め、研究や開発を行うという、筑波大学の情報科学特別演習という科目も兼ねており、定期的にDB設計などに関しては担当教員からのアドバイスの頂いておりました。
当初は母親のみが販売するという話だったので、そのように開発を行っていたのですが、夏休み辺りに母親から、「〇〇さんも出品してみたいんだって。」という話が舞い込んできて、そこから実装のハードルがとんでもなく上がったのですが、プラットフォーム型ECサイトの開発へと方針を転換していくこととなります。
24年1月頃、やっと形が見えてきたのですが、コードを友人に見せたところ、これは保守性がとても悪く、管理に手が負えなくなると指摘を受けました。確かに今思えば、よくこんなコードで公開しようとしていたものだと思うのですが、それからまたスクラッチからの開発がスタートしました。書き直すのにあたって設計をその友達に手伝ってもらいました。途中で忙しくなって開発から抜けてしまったのですが、立ち上げ時に協力してもらった彼にはとても感謝しています。ありがとう。
友人達にはずっと3月いっぱいに公開すると言い続けていたので、それを目標に死にものぐるいで実装してきました。1月末から実装し始めてバックエンドは1万行近く書きました。
そして、やっと3/31の22時頃にサービスのテストリリースを達成することができました!!!
ただ、このサイトはまだテストカードでしか決済できず、商品や金銭のやり取りはまだ行えないため、プロジェクトは完了したわけではありませんが、本当にあと一歩というところまで来ました。バックエンドに関してはほとんど開発が終わっているのですが、テストを書きながら実装していたのでフロントエンドに着手するタイミングが遅れてしまったため、まだもう少しかかるという感じです。これから本番公開に向けてフロントエンドのやりきれていない箇所の実装と、テストリリースでは実装していなかったフロントエンドの出品者側の実装を行う予定です。
# 技術的な話
ここからはプロジェクトで使われている技術スタックについて書いていこうと思います。
(ここで説明しているものは主に1月から書き直したプロジェクトのものです。)
# フレームワーク
使用したフレームワークはRESTAPIとgRPCです。
基本的な実装はすべてRESTAPIで行っており、管理者関連の実装をgRPCで行いました。
本当は全てRESTAPIでも良かったのですが、今までと同じようにしてエンドポイントを定義して実装するだけだと刺激が足りないと思い、gRPCで実装してみたという感じです。gRPCはprotoファイルを使いまわすことができ、すごく直感的に実装することができたので、そのうちgRPCのみを使用したシステムを実装したいなと思いました。
# 言語
フロントエンドをTypeScript
、バックエンドをGolang
で開発しました。
選定理由ですが、フロントエンドはTypeScriptに強い友人が多かったからで、バックエンドはGolangをおすすめされて触ってみたら、とても感触が良く、使いやすかったからです。パフォーマンスなどで選んでいるわけではなく、手にとても合っていたので採用しました。
# 言語でのフレームワーク
フロントエンドはNext.JS
、バックエンドはGin
を採用しました。
Next.JSではApp routerを採用しています。(旧実装ではPage routerでした。)
Next.JSで開発した理由はドキュメントが豊富なところと、友人が触っているプロジェクトの多くで採用されていたため、実力がついてきたら貢献できるかもしれないと思ったからです。
実際のところ、現在友人達によるプロジェクトに途中参加し、issueを潰す役目に回っております。立ち位置としてはページの具体実装よりかは、エラーハンドリングや挙動の修正をメインで行っております。
バックエンドでGinを採用した理由としてはGolangのメジャーなフレームワークであることもあるのですが、やはり本当に未経験だったときにはじめて動かすことができたフレームワークということもあり、書き直しをする際にも楽だからという点で採用しました。書き直しを行う際、ほかのフレームワークではchiを検討していました。
# テスト
再実装を行う際に力を入れたのはテストです。先輩方からテストの重要性を教わり、書き直しを行うタイミングでちゃんとテストをかけるようになりたいと思い、先輩が書いたコードを読みながら見様見真似で実装していきました。
参考にしたリポジトリ:
テストを書いていく中で、small、medium、largeテストと、規模を大きくしながらテストを書くことを意識していきました。
最近はgithub Actionsで依存関係をもたせてCIを回すことに気持ちを向けていて、少しずつではありますが、CI/CDにも関心が出てきました。
# 開発手法
書き直しをするにあたってOBの先輩から Dependency Injection という依存性注入と呼ばれる開発手法を教えていただきました。これをすることでテストをより書きやすく、保守性の高いコードをかけるということを知り、その開発手法を勉強しながら書き直しを進めていきました。
Dependency Injectionは最初はなんのためにやっているのかあまり理解できなかったのですが、とりあえずやってみるということでやっていくと、すぐにその威力に思い知らされました。うまく関心の分離ができていたので、旧実装よりも重厚な実装を実現することに成功しました。更にモックを作ることもできていたので、今実装するべきはどこなのかを明確にしながら開発することができ、とても開発体験が良かったです。
# データベース
データベースはmariaDBを使用しています。
データ構造はコロコロ変わっていましたが現在はこの構造で安定しています。
上下で起動しているサーバーを分けていて、これからtransactionの方のDBは定期的にダンプを取って保管しようと考えています。
# イメージなどのリソース保管場所
cloudflare R2を使用しております。ドメインをcloudflareで管理しているため使いやすく、無料枠があるので採用しました。CDNでのキャッシュも魅力的な点でした。ちなみにこのブログもcloudflare pagesで公開しております。
# メールサーバー
cloudflare Email routingを使用して、gmail経由で送信しております。ただこの体制はメールをたくさん送信するようなサービスになってしまうとgmailの制限がかかるため、少し不安要素ではあります。
# 外部ライブラリ
# ユーザー認証
firebaseSDKを使用しております。ユーザー認証は手前実装だとリスクしかないと考えたからです。
旧実装ではfirebaseから一度だけjwtを取得してそのあとの通信は独自に発行したtokenをcookieに保存してやり取りするというものだったのですが、firebaseの機能を全然活かせないことや、一度取得したセッションが何らかの影響で期限切れになった場合にそれを検知することができないこと、複数端末での同時ログインが実現できないことから廃止しました。
現在の実装ではauthを始めに取得し、そのauthを使いまわし、バックエンドへの毎リクエストごとにjwtを載せる実装をしています。
# 決済
Stripe SDKを使用しております。決済はStripeに一任しております。そのうちpaypayも使用可能にしたいと考えています。現在の実装では複数サービスに対応できる形なので、余力があればやりたいと考えています。 連結アカウントなどの機能によって出品者が登録した口座に自動送金できるため、Stripeを採用しております。
# CSSライブラリ
chakra UIを使用しています(一部material UI)。ただこれは暫定なので変更することがあるかもしれません。旧実装ではmaterial UIを使っていました。
# 技術構成
フロントエンド・バックエンド構成で、nginxでリバースプロキシされており、認証・決済を上記の通り外部ライブラリにまかせているという形を取っています。
# 終わりに
テストリリースまで約一年間かかりましたが、ここまでこれたのはずっと気持ちを持ち続けることができたことにもあると思いますが、それ以上に先輩方や友人達に恵まれていたからだと思います。charis worksのcharisとは感謝という意味があります。最初は母親が全てに感謝するという意味合いでつけたこのプロジェクト名ですが、これまでお世話になってきた方々に感謝しています。本当にありがとうございます。
まだ本番リリースではないこのプロジェクトですが、なんとか本番を目指して開発を続けていきたいと思います!!!