巨人の足元でたじlog

そうして言葉を軽んじるから――― 君は私の言葉を聞き逃す

GoをCloud Runで動かしてみる。コードとDockerfileそれぞれでデプロイ

Goをデプロイしてみます。

 

qiita.com

 

前提条件として、GCPはちょっと知っていないとだめそうですね。

 

GCPは大昔触ったことがありましたが、プロジェクトとかの分け方がよくわかってないため、そのあたりからおさらいでやっていきます。

 

qiita.com

 

これを参考にしてやってみます。

まず、クイックスタートをやってみたいと思います。

その前に、公式のドキュメントもチェックしておきます。

チュートリアル

cloud.google.com

 

チュートリアルは、なんかトピックが多すぎて、だめだ。

 

cloud.google.com

クイックスタートはなんか軽そうだし、上のQiitaの記事でも参考にしていたので、これを確認します。

cloud.google.com

ちょうどGoのやつがありました。これでいいじゃん。

「Cloud Shell」でできるみたいなので、これで進める。

1. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

プロジェクトを作成します。

作成できました。

 

2. Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください。

大丈夫そうでした。というより、新規アカウントで作成したので、そのときに登録しました。

300$クレジットげっと!

 

3. Google Cloud CLI をインストールして初期化します。

 

3-1. gcloudをmacにinstallしてみます。

Quickstart: Install the Google Cloud CLI  |  Google Cloud CLI Documentation

 

と、これをやろうとしたのですが、brewでありそうなので、そっちでやってみます。

formulae.brew.sh

zenn.dev

brewのバージョンを確認

% brew -v
Homebrew 3.6.3
Homebrew/homebrew-core (git revision 3de6ff81a00; last commit 2022-10-01)
Homebrew/homebrew-cask (git revision 81521f14c8; last commit 2022-10-01)

 

installします。

$ brew install --cask google-cloud-sdk

完了後、以下を.zshrcに追記

source "$(brew --prefix)/Caskroom/google-cloud-sdk/latest/google-cloud-sdk/path.zsh.inc"

以下実行

source ~/.zshrc

これでパスが通りましたわ。

% gcloud -v
Google Cloud SDK 405.0.0
bq 2.0.78
core 2022.09.30
gcloud-crc32c 1.0.0
gsutil 5.14

初期化も必要みたいなので、やっておきます。

$ gcloud init

ブラウザで認証画面になるので、使いたいアカウントを設定します。

使用するプロジェクトもここで選ぶように言われるので選びます。

 

なんかzennの記事だとできなかったので、普通にbrewの指示通りにやったらできました。やはり公式が正義か。。

 

Cloud Run サービスのデフォルト プロジェクトを設定するには

$ gcloud config set project PROJECT_ID
Updated property [core/project].

(gcloud initで選択済みなのでこれは必要なさそうだったが、まあいい)

 

4. サンプル アプリケーションを作成する

helloworldディレクトリを作成して、

go.modファイルを以下で作成

module github.com/GoogleCloudPlatform/golang-samples/run/helloworld

go 1.13

 

以下でも良いようだが、goのバージョンが上がっていそうなので、素直に上記ファイルを作成した。

 

$ go mod init

 

main.goを以下で作成

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
)

func main() {
    log.Print("starting server...")
    http.HandleFunc("/", handler)

    // Determin port for HTTP service.
    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
        log.Printf("defaulting to port %s", port)
    }

    // Start HTTP server.
    log.Printf("listening on port %s", port)
    if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal(err)
    }
}

func handler(w http.ResponseWriter, r *http.Request) {
    name := os.Getenv("NAME")
    if name == "" {
        name = "World"
    }
    fmt.Fprintf(w, "Hello %s!\n", name)
}

 

5. ソースから Cloud Run にデプロイする

main.goのあるディレクトリで以下コマンド

$ gcloud run deploy

諸々聞かれるオプションを適当に設定していく。

 

This command is equivalent to running `gcloud builds submit --pack image=[IMAGE] y` and `gcloud run deploy y --image [IMAGE]`

 

と、エラーになった。

ERROR: (gcloud.run.deploy) INVALID_ARGUMENT: could not resolve source: googleapi: Error 403: 385636020183@cloudbuild.gserviceaccount.com does not have storage.objects.get access to the Google Cloud Storage object., forbiddenさ

アカウント作ってから何もいじってないからadminユーザーとして実行しているような気がするんだがー

 

もう一回実行してみたら、行けました。

たぶん途中で待ち時間の間にオプションに変な文字が入ってしまっていて正しく入力できていなかったのかもしれません。

 

Service URL: https://helloworld-xxxxxxxxxxxx-x.a.run.app

との表示があったのでアクセスすると、Hello, Worldの文字が!

成功!?

デプロイ簡単すぎわろたぁ〜

クイックスタートはここで終わりです。

すぐに終わって物足りない感あったので、もう少し見てみます。

 

<サービスを開発する>

cloud.google.com

軽く読みました。

 

 

<全般的な開発のヒント>

cloud.google.com

 

以下自分が気になった部分の引用と、まとめです。

・バックグラウンド アクティビティ

・Cloud Run はリクエストを 10 秒以上維持しないため、コンテナの起動に 10 秒以上かかる場合は、最小インスタンス数を 1 以上に設定する必要があります。

・Cloud Run では、リクエスト間でサービスの状態が維持されるとは限りません。ただし、Cloud Run はコンテナ インスタンスを再利用してトラフィックの処理を継続するため、グローバル スコープで変数を宣言することで、その値を以降の呼び出しで再利用できます。個々のリクエストで値が再利用されるかどうかを事前に確認することはできません。

グローバル変数の扱いに注意する

・alpineかscratch等、小さいサイズのベースイメージを使用する。

 

<コンテナをビルドする>

cloud.google.com

 

Dockerfileからデプロイ

大枠はこれで良さそうですが、Dockerfileとか含め、実際に絶対に動くやつでまずは確認したいので、そういった情報を探してみます。

 

qiita.com

 

これを参考にしてやってみる。

新しいプロジェクトを作ってトライします。

`main.go`

package main

import (
    "fmt"
    "net/http"
    "os"
    "strconv"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello world\n")
}

func main() {
    port, _ := strconv.Atoi(os.Args[1])
    fmt.Printf("Starting server at Port %d", port)
    http.HandleFunc("/", handler)
    http.ListenAndServe(fmt.Sprintf(":%d", port), nil)
}

以下実行

go run main.go 3000

ブラウザからhttp://localhost:3000 にアクセス。

「Hello, world」が表示されました。良さそうです。

 

`Dockerfile`

FROM golang:latest as builder

ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
WORKDIR /myprojectsample
COPY . .
RUN go build main.go

# runtime image
FROM alpine
COPY --from=builder /myprojectsample /app

CMD /app/main $PORT

 

docker build -t myprojectsample .

→成功。

 

% docker run -e "PORT=3000" -p 3000:3000 -t farsidesample

http://localhost:3000 にアクセスして成功。hello, worldが表示される。

 

Container RegistryへのPush

Container RegistryよりもArtifact Registryの方が推奨されているみたいなので、使ってみるか?

一旦GCRの方でやってみて、すぐ変更できそうな気もするのであとでやる。

 

cloud.google.com

 

 

Container Registryにまずはpushしてみる。

gcloud auth configure-docker

 

push するイメージを取得する

docker pull gcr.io/google-samples/hello-app:1.0

 

イメージを Container Registry に追加する

docker tag gcr.io/google-samples/hello-app:1.0 gcr.io/PROJECT_ID/quickstart-image:tag1

 

イメージを Container Registry に push する

docker push gcr.io/PROJECT_ID/quickstart-image:tag1

 

GCPコンソールにイメージが確認できました。

Artifact Registryのクイックスタートも見てみます。

 

Artifact Registryのクイックスタート

cloud.google.com

Dockerリポジトリを作成する

gcloud artifacts repositories create quickstart-docker-repo --repository-format=docker \
--location=asia-northeast1 --description="Docker repository"

 

リポジトリが作成されたことを確認

gcloud artifacts repositories list

→OK

 

認証を構成

gcloud auth configure-docker asia-northeast1-docker.pkg.dev

 

pushするイメージを取得

docker pull us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0

 

イメージにレジストリ名をタグ付けする

docker tag us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0 \
asia-northeast1-docker.pkg.dev/PROJECT/quickstart-docker-repo/quickstart-image:tag1

 

イメージをArtifact Registryにpushする

docker push asia-northeast1-docker.pkg.dev/PROJECT/quickstart-docker-repo/quickstart-image:tag1

 

GCPコンソールでイメージがpushされていることが確認できました!

 

 

qiitaの記事に戻る

imageのpushをします。

qiitaの記事ではContainer Registryを使っていましたが、Artifact Registryを使っていきます。

先にArtifact RegistryのGCPコンソールからリポジトリを作っておきます。

 

イメージにタグをつける

docker tag myprojectsample asia-northeast1-docker.pkg.dev/PROJECT_ID/myprojectsample/sample:firstbuild

 

pushする

docker push asia-northeast1-docker.pkg.dev/PROJECT_ID/myprojectsample/sample:firstbuild

→ GCPコンソールから確認できました。

 

サービスの作成

うまくいかない。

イメージからCloud Runにデプロイをやってみると、以下のエラーメッセージが出てデプロイ失敗してしまいました。

The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. 

 

localでは動いていたのに、、

cloud.google.com

これもやってみました。

gcloud beta code dev

これではちゃんと表示されていたので、なおさらおかしいですね。

 

 

以下のDockerfileとmain.goでやってみてもだめでした。

github.com

 

これを見て解決できるか?

cloud.google.com

 

ポートは問題ないと思うけどなぁ。

注: ARM ベースのマシンでコンテナ イメージを作成した場合、Cloud Run で意図したとおりに動作しないことがあります。この問題を解決するには、Cloud Build を使用してイメージをビルドします。

 

ARMベースじゃなくてApple M1 Proなんだけど、もしかしてこのあたりが問題なのか?

結論、以下で解決しました。

stackoverflow.com

 

以下オプションを付けてbuildしてみる。

--platform linux/amd64

 

これでbuildしたらいけました!

 

Artifact RegistryのイメージからCloud Runにデプロイを選択して、リージョンはasia-northeast1にして、認証は「未認証の呼び出しを許可」にして「作成」

すると、サービスが作成されて、表示されたURLにアクセスすると、Hello World!の文字が!

 

くぅ〜これにて完結です!

 

このあたりは一回どっかできれいにまとめたいところ。

個人開発でのサーバー料金等の運用コストについて調査・検討

さて、そろそろ本格的にwebサービスの開発に着手していきたいと思いますが。

 

まず、全体の構成として

Go(gin) + Next.js

というのは決定しています。

そしてNext.jsをデプロイする先はvercelでほぼ決まりでしょう。

企業で本番環境で使うことはあまりないようなのですが、個人開発にとってはもってこいです。無料かつデプロイが超簡単なので。

herokuのノリですかね。

 

APIサーバー

AWSが親しみ慣れているが、せっかく個人開発なので、使ったことないサービスとか馴染みないサービスを使ってみたいところ。

なので、GCPを使おうと。

CloudRunが良さそう。

cloud-ace.jp

 

コンテナを簡単にいい感じにデプロイしたり、マネージしてくれたりするやつ?

料金も使わなければ安そう。

 

dev.classmethod.jp

 

AWSのApp Runnerみたいなやつとのこと。

App Runnerも初見だった。

見ると2021年5月リリースなので、自分がエンジニア休憩していた時期だった。

友人にはCloud RunはAWSでいうECSみたいな感じって聞いていたが、それよりも簡単そう。VPCとかネットワークとかセキュリティグループとかの設定も皆無らしい。強い。

 

zenn.dev

 

Cloud RunとCloud SQLについて書いてあった。

さらっとCloud SQLのミニマム料金書いてあった。12$くらいと。ちょっと調べてみても出てこなかったので助かる。

 

やはりCloud Runは良さそう。

ベストではなくてもベターではありそう。一回使ってみたいってのはあるので、これを採用する。

 

料金について

リクエストの処理中のみCPUを割り当てるサービスの料金

CPU: 毎月最初の 180,000 vCPU 秒は無料

メモリ: 毎月最初の 360,000 GiB 秒は無料

リクエスト: 毎月 200 万リクエストは無料

 

CPUが常に割り当てられるサービス

CPU: 46.656$/月(無料枠を加味していない)

メモリ: 5.184$/月(無料枠を加味していない)

 

これは後者は高すぎるので、前者でやる。

前者だと無料でできそう。

 

データベース

今回は普通にRDBMSでテーブルの設計をなんとなく考えていたので、となるとCloud Runを使う以上GCPでやるのがやりやすそうで、つまりはCloud SQLが有力です。

ネックになるのは料金。

個人開発者にとってこれは死活問題。

thr3a.hatenablog.com

 

公式を見てみても、料金体系がよくわかりづらい。

これによると、(4年前の情報だけども)ミニマムで月額1500円弱くらい。

 

AWSのRDSでも東京リージョンでミニマムでも18$/月くらいかかるので、1500円だったら飲み込めるか。。

 

あるいは、無料で使える?データベースとしてFirebaseを選択するか。

しかし、今回GoとNext.jsが所見なので、ここにFirebaseも入ってくると流石に勉強期間が長過ぎてだれる恐れがあるので、やめときたい。

Firebaseそのものもそうだし、そもそものNoSQLでのデータのリレーションとかどうするのかとかもよくわかっていないため、かなり学習コストが高い。

それにGoを今後使っていきたいとして、殆どの企業では基本的にはRDBMSを使っている?と思うので、そのあたりにスムーズに入れるように、一旦今回はNo NoSQLでいきます。

 

料金について

vCPU: $39.19 per vCPU・月

メモリ: $6.64 per GB・月

 

ストレージ: HDD ストレージ容量: 1 GB あたり $0.117/月

ネットワーク: 内向き・外向きともにGoogleプロダクトなら大陸内は無料

 

インスタンス: 一番安いやつで$9.96/月

 

CPUとメモリ料金に加えて、インスタンス料金もかかるってこと?

インスタンスにはCPUとメモリは含まれていないの?

sharedの場合は、インスタンス料金だけでいけるような雰囲気がある。

 

 

これによると、1,646円。まあ許容できる。

 

あとはドメイン代くらいか。

全体で月2000円くらいで運用できそうかな。

 

がんばります。

Go言語のデータベース連携ライブラリの選定

ORMはsql-boiler
migrationはgoose

 

をGoをよく使っている友人に進められたので、調べてみます。

 

SQLBoilerについて

zenn.dev

 

sql-boilerの他にORMライブラリは

・ GORM

・sqlx

などがある。

sql-boilerはマイグレーションの機能は入っていないが、それは他のマイグレーションライブラリを組み合わせれば良いので問題にはならないと。

コンパイル時にエラーが出るので、誤りにすぐ気がつくと。

 

公式ドキュメントを見てみます。

 

github.com

SQLBoiler は、データベーススキーマに合わせた Go ORM を生成するツールです。

(gorm/gorp のような) "コードファースト" とは対照的に、"データベースファースト" な ORM です。つまり、最初にデータベーススキーマを作成する必要があります。データベースのライフサイクルのこの部分を管理するために、sql-migrateやその他の移行ツールのようなものを使ってください。

 

gooseについて

github.com

 

・設定ファイルなし

 

・デフォルトのgooseバイナリはSQLファイルのみマイグレート可能

 

・Goのマイグレーション
Go migrations: Go migrations 関数を goose バイナリからオンザフライでビルドすることはありません。
代わりに、独自のカスタム goose バイナリを作成し、Go マイグレーション関数を明示的に登録し、独自の *sql.DB 接続で複雑なマイグレーションを実行することができます。
Goマイグレーション関数では、*sql.Tx引数を使用すれば、SQLトランザクション内でコードを実行することができます。


・gooseのpkgはバイナリから切り離されています。
goose pkgはもうSQLドライバを登録しないので、コードベース内でのドライバのpanic()衝突がありません!
goose pkg は、もうベンダーへの依存を一切持ちません。

 

・デフォルトでタイムスタンプ付きのマイグレーションを使用しますが、開発工程ではタイムスタンプを使用し、実運用工程ではシーケンシャルバージョンを使用するハイブリッドアプローチを推奨します。

 

・allow-missing フラグを指定することで、missing (out-of-order) migrations をサポートします。ライブラリとして使用する場合は、関数オプション goose.WithAllowMissing() を Up, UpTo または UpByOne に指定してください。

 

スキーマテーブルで追跡することなく、アドホックマイグレーションを適用することをサポートします。移行が適用された後にデータベースをシードするのに便利です。no-versioning フラグまたは関数オプション goose.WithNoVersioning() を使用します。

 

DeepL翻訳より。

railsActiveRecordのノリでいけるってことでしょうか?

そう信じてやっていきます。

 

 

 

リフレクションとは?

ちょいちょいリフレクションという単語が出てきているけど、聞いたことなかった。

 

pokuwagata.hatenablog.com

 

実行時にわかるデータを使ってなにかの処理をさせたいときに使う、のかな?

なんとなくはわかったが、曖昧です。

概念はわかったような気がするけど、実際にこれをどう使うのか?なんで使いたいのかがよく理解できていないです。

これは一旦置いてお生きます。

 

 

 

データベース連携方針まとめ

色々比較検討した上で、決めていきたかったのですが、メリットデメリットを考えられるほどつらみとかを理解していないってのもあり、判断軸がないです。

なので、友人が勧めてくれたSQL-Boilerとgooseを脳死で使っていきたいと思います。

Go言語のフレームワークGinをやってみる

チュートリアルっぽいのがあったので、それをやってみます。

最近の心がけとして、なるべく公式コンテンツから着手してみることにしています。

最近もNext.jsを学習していたのですが、今までだったらUdemyで手頃な講座を見繕って進めていたと思うのですが、そういうのって結局公式のチュートリアルを解説しているだけのものだったりするので、だったらまずは公式チュートリアルをやってみようと思った次第です。

講座だと情報が古いし、習得したい技術に必ずしも日本語講座が有るとも限らないので、中長期的に見て公式情報から習得する術を身に着けたいです。

 

ということで、Ginのチュートリアルっぽいのを公式から見つけました。

go.dev

 

これを進めていきます。

 

終わりました。

 

RESTfulのルーティング関連をうまく処理できるようにしてくれているのがginっていう認識です。

そんなに多くのことをやっていないような気もしています。まだそこまで踏み込んでいないだけかもしれないですが。

このチュートリアルではメモリでデータの管理をしていたので、DBとデータをやり取りするってなるともう少し量も増えてくるのかなと思います。

とはいえ、そうなってくるとそっちはDB連携用の別のパッケージとかライブラリとか使うことになるのだと思うので、Ginの責務的には、ルーティングして特定の関数を呼び出すこと?だけなのかなっていう感じ。

 

さて、Ginが何となくわかったので、そろそろ本来やりたいwebサービス開発に着手できるかな?

フロントエンド初心者がNext.jsを習得してみる

チュートリアルをやっていきたいと思います。
https://nextjs.org/learn/basics/create-nextjs-app しかし、英語しかないのか?

https://nextjs-ja-translation-docs.vercel.app/docs/getting-started 一応非公式日本語翻訳サイトはあったが、これは新鮮なのか?
これは、新鮮かどうか以前にチュートリアルはないっぽい.

本家英語サイトをDeepLを駆使して読んでみるか。
そろそろ日本語やってみた記事を読むレベルから脱却したいので。
ページまるごと翻訳だとDeepLだと有料なので、なくなくGoogle翻訳で対応することにした。 月額750円はちょっと高い、、300円なら考えた、、!
しかし、ぱっと見Google翻訳でも精度悪くなさそう。よし。

チュートリアルを進めていく

全体像把握

ブログアプリを作るチュートリアル
- Next.js アプリを作成する
- ページ間を移動する
- アセット、メタデータCSS
- 事前レンダリングとデータ取得
- 動的ルート
- API ルート
- Next.js アプリのデプロイ

このあとも検索エンジン最適化の章もありましたが、そこは一旦保留で良いかなと思います。

Next.js アプリを作成する

前提知識としてJavascriptとReactが必要とのこと。
Reactのチュートリアルやろうっかな。
3年くらい前に一度途中までやった気がする。同じチュートリアルかどうかはわからないけど。
Nextを途中まで進めてみて、React前提の知識が多すぎたら中断してReactのチュートリアルを進めることにする。○×ゲームを作るチュートリアル。面白そうだし、そんな大変でもなさそうなので。
やっちゃうか?2時間くらいで終わりそう。
やっちゃう。 https://ja.reactjs.org/tutorial/tutorial.html

ブラウザ上で実行できるplaygroundが用意されているので、それを使用します。環境構築は別途Next.jsで必要になると思うので。

チュートリアルやった。
最後の「タイムトラベル機能の追加」は流してやった。
いよいよ本番のNext.jsに入る。

Next.js チュートリアル

node.jsの確認

node -v
v16.16.0

入っていた。

npx create-next-app nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/master/basics/learn-starter"

開発サーバーを立ち上げる

npm run dev

早っ!
これで
http://localhost:3000/
にアクセスするだけで表示できる。

indexページを変更。
変更がサーバーやブラウザの再起動をせずにすぐにブラウザに反映される。
これがFast Refleshという。ストレスなく開発できそう。

画像はいい感じにリサイズとかして配信してくれる。
ブラウザの表示領域(view-port)に来たときに読み込まれる。

サードパーティーのscriptの読み込みのタイミングも、ブラウザが暇なときにやってくれるオプションとかある。next/scriptでやる

Next.js用のvscode拡張機能を入れたい

JSXの部分を書くときにコード補完がうまく働いてくれない。 JS JSX Snippetsを入れてみる。
効かなさそうだな。。

https://www.servs.jp/emmet-setting-when-html-tags-are-not-completed-by-reacts-jsx-in-vscode-2215/ これだ、最高、ありがとう。

リンクのコードをバックグラウンドで自動的にプリフェッチしてくるので、ページ遷移が一瞬。

プリレンダリング データフェッチについて話す前に、Next.jsの最も重要な概念のひとつについて説明します。プリレンダリングです。

デフォルトでは、Next.jsはすべてのページをプリレンダリングします。これは、クライアントサイドのJavaScriptですべてをおこなうのではなく、Next.jsがあらかじめ各ページのHTMLを生成しておくことを意味します。プリレンダリングは、パフォーマンスとSEOの向上につながります。

生成された各HTMLは、そのページに必要な最小限のJavaScriptコードと関連付けられています。ブラウザがページを読み込むと、そのJavaScriptコードが実行され、ページが完全にインタラクティブになります。(このプロセスをハイドレーションと呼びます)。

メタデータを読み取るためのやつをinstall

npm install gray-matter

ローカルファイルストレージからデータを取得する。
Static Generation

静的生成はビルド時にHTMLをプリレンダリングする。プリレンダリングされたHTMLは、リクエストごとに再利用される。
サーバーサイドレンダリングは、リクエストごとにHTMLを生成するプリレンダリング方式。
ページごとにどちらの方式を使用するか選択することができる。

ユーザーダッシュボードとかはSEO関係ないし、CSRでいい。
クライアントサイトレンダリングは、ビルド済みのHTMLを返して、必要な部分だけクライアントが別途リクエストを送って、レスポンスをHTMLに組み込む。合ってる?

vscodeのdiffを見る拡張機能

https://pa-tu.work/blog/vscode-clipboard-diff ファイル保存をしないでもdiffが取れる。
ファイル単位じゃなくて、同じファイルの中の選択した部分同士を比較することもできる。
これで正解コードと自分で書いたコードの差分を見てtypoとかをぱっと探せるようになった。

Module not found: Can't resolve 'fs' エラー

https://fullstacklife.net/programming/nextjs/nextjs-module-not-found-cant-resolve-fs/

これをみて、設定ファイル変更するかーと思ったけど、Next.js用のGithub Issueに回答があった。 https://github.com/vercel/next.js/discussions/12124

しかし、結論、チュートリアル内でどうすれば良いのかがわからなかった。
Next.jsにもう少し触れてみたら、ああなるほどねってなるのかもしれないが。

https://gotohayato.com/content/553/ これもちょっと、チュートリアルに当てはめて考えることができていない。全体を理解・把握していないからだ。

remarkのインストール

npm install remark remark-html

date-fnsのインストール

npm install date-fns

GoとNext.jsを使った個人開発アプリケーションの構成を構想する

参考記事①

qiita.com

Next.jsはVercelにデプロイ
GoはCloudRun
RDSはCloudSQL
という構成。うん。これが一番シンプルでいい気がする。 ほかも見てみます。

参考記事②

zenn.dev

Go × Next.js × GraphQL というパターン。
これもまあある構成な気がしています。
これの場合、GraphQLってリソースって必要なんでしょうか?
GraphQLの位置づけがまだわかっていないです。
しかし、一度に色んな技術を盛り込みすぎると大変になりそうなので、一旦はGraphQLはなしで開発を進めてみて、リリースした後にGraphQLを入れ込んでみるのがいいかなと思っています。
なにかのつらみがあってGraphQLをみんな導入しているはずなので、そのつらみを一回小規模なサービスで経験しておいてから、だからこれが有るといいんだよと言えるようにしてみたいためです。

参考記事③

zenn.dev

GraphQLは後回しにしようと思いましたが、この記事を見て半日ほどで学習したと記載あったので、一度どんなものなのかの概念だけ把握しておくのはありかなと思いした。
と思ったんですが、GraphQLの周辺ツールに1〜2週間くらいかかっていたので、やはり一旦保留です。
いや、GraphQLの雰囲気だけ掴んでおいて、実装はまたの機会ってことにするのが落としどころかな?

結論

ということで、シンプルにGo + Next.jsという構成にしてみたいと思います。 参考記事①の通りに

Next.jsはVercelにデプロイ
GoはCloudRun
RDSはCloudSQL

という構成でやってみようかと思います。

Goのフレームワーク選定

参考記事①

qiita.com

自前でスクラッチで書いてみるのもありか。
しかし、初手でスクラッチで書くのは諸刃の剣だなって気がしています。
挙動を理解できるので良いと思うのですが、いかんせん開発スピードが出ずにモチベーションが下がる可能性があります。
かつ、フレームワークが隠蔽してくれている処理をいちいち書く必要があるので、考えることが多いです。それ故に勉強にはなるのですが。
なので、今回はやはりフレームワークを使用したいと思います。
フレームワークをある程度使えるようになってから、スクラッチで実装してみて、そのときにフレームワークで色んなことをやってくれていたんだなぁとしみじみと感じるスタイルを取ることにします。

参考記事②

qiita.com

以前も調べていてGinが覇権穫りつつあるのかなと思っていましたが、再度確認。
これは思考停止でGinでいい気がします。
一応、Next.jsとGinの組み合わせで罠とかないかなと調べてみます。
APIサーバーとして使うので、サーバーサイドのフレームワークはNext.jsからした関係ないと思いますが。

参考記事③

zenn.dev

Gin使ってますね。
というかこれ、開発環境と本番環境のインフラとかも説明してくれているので、すごく良さそうですそのあたりはまだちゃんと見ていないですが、あとで役立ちそうです。

ということで、GoのフレームワークはGinで 進めてみたいと思います。

どういう順番で手を付けるか

自分の現場としては、Goはローカルでスクラッチで簡単なTodoアプリは作ったことある。
Next.jsは全くのはじめまして、Reactはチュートリアルレベルだけかじったことがある、TypeScriptはReactとNestJSをちょっと触ったことがあるので、そのときになんとなく触ってみた。
くらいな感じです。
そもそもの開発の流れとしては、一回Next.jsとGoを疎通だけできるような状態にして、そこからページ単位(API単位)で機能を作っていく感じが正しいのかなって気がしています。
なんとなくフロント側で使いたいAPIを定義(想定)して開発して、それに合うようなAPIをバックエンドで開発するという流れなのかなと言う気がしています。
でも、そうするとフロントの動作確認とかはどうするんだろう?って気もしてます。
モックのデータだけ返すようなAPIを一時的にバックエンドでベタ書きの決め打ちとかで作って動作確認→問題なさそうならバックエンドで実装という流れなのかな?
いや、今回はとりあえず個人開発なので、両方同期的に開発できそうだからそこまで気にしなくてもいいっか。
railsのようなフルスタックフレームワークでもerbとcontrollerも両方いじりながら開発するので、そのノリで。
ただ、フロントとバックエンドでチームが分かれているサービスとかではどう進めていくのか気になるところです。
フロントが先な気がするな。
しかしここにGraphQLとかも入ってくるといよいよわからなくなってくるな。みんなで開発するのって大変だなぁ。

学習方法

Go(Gin)とNext.jsはそれぞれ独立して学習を進めて問題なさそうに思います。
一旦Next.jsを一通りやってみて、その後Ginも触る。
それが終わったらもうサービスの開発に取り掛かりたいと思います。

ようやく進められそうです。

10月末までにリリースを目指して開発を進めていきます!

今後使っていきたい技術

メモ書き程度に。
言葉の粒度はまちまちですが、以下を触ってみたいなと思っています。
どこかのタイミングでプロジェクトに入れ込めれば良いなと構想しています。
- GraphQL
- Firebase
- Go
- React(TypeScript)
- GCP
- テスト
- gRCP
- クリーンアーキテクチャ
- テスト駆動開発
- ドメイン駆動開発
- GithubActions
- k8s

Next.jsってどうなの? フロントエンド初心者が調べてみた

自分の現在の技術スタック

インフラ: AWSを中心としたクラウドインフラはある程度理解している。GCPもちょっと
サーバーサイド: rails, cakephpなどのフルスタックフレームワークはわかる。言語はpython, ruby, phpなどが多め。
フロントエンド: rails等のテンプレートとしての使い方しか基本的にはわからない。以前ReactとかNustJSとかのUdemy講座はやってみて、なんとなくの書き方等の雰囲気はわかっているけど、具体的にどこで動かすのかとか、サーバーサイドとかとの連携はわかっていない。

背景

という前提で、今回Reactをやってみたいと思って、その中でも色んな求人票を見ているとNext.jsがよく見るので、これを個人開発で使ってみたいなと思った次第です。また、サーバーサイドではGoを使ってみたいという条件もありました。
自分の技術力アップのために、静的型付け言語を一度やってみたいと思っており、サーバーサイド言語としては色々比較検討しましたが、これやっとけば間違いないでしょ的にGo、そしてフロントエンドもわかるようになって、一人で小規模なサービスなら作れるくらいになりたいと思い、何かしらに手を付けようと思いました。
VueかReact(他にもありますかね?)の中の選択肢で、qiitaのタグの数は同じくらいで、stackoverflowのタグの数は、reactが圧倒的に多くて(これはタグが分散されている問題もあるかもしれないです)、GoogleTrendでは2021年末あたりからreactの勢いが増してきているように見えました。
なので、reactを選んでおけば無難かなと思いました。
VueとReactでは、自分の印象ではVueの方がReactよりも習得難易度がちょっと低いという認識でしたが、ReactはReact Native?とかでスマホアプリも作れるとのことで、これを使えるようになったら幅が広がりそうだなと思い、Reactを使ってみる前提で考えました。
そこで、単純に求人票などでよくNext.jsを見るなと思い、これに興味を持ちました。

しかし、そもそもNext.jsってなんなのか?Reactとの違いは?他のどんな技術と組み合わせることができるの?サービス運用のどの部分を担うの?どこで動くものなの?他に勢いのある競合技術はないの?本当にNext.jsの選択でいいの?
と、まだわからないことが多かったため、一度整理しつつ、個人開発にアクセルを踏めるようなところまで調べてみたいと思いました。

参考記事①

udemy.benesse.co.jp

Next.jsとは、Reactをベースに開発された、フロントエンドフレームワークです

Next.jsとReactの1番の違いは、サーバー機能の有無です。Next.jsはサーバー機能を持っていますが、Reactにはサーバー機能がありません。つまり、Next.jsは単体でWebアプリを動作させることができますが、Reactは別途サーバーを用意する必要があります。サーバーを用意するということは、サーバー用のモジュールをインストールし、ディレクトリ構成などを検討する必要があるため、Reactのほうが学習コストや難易度が高くなります。

参考記事②

qiita.com

とても良くまとまっていて参考になりました。
Next.jsを使う際のユーザー的なメリットなど理解できました。
高速化とかSEOとかは今回は特にそこまで意識する必要がないので、どちらかというとアーキテクチャ的に作りやすいか、開発を高速にスムーズに行うことができるか?などの観点で見てみたいと思います。

まず、Reactがどういう構成で使われるかの把握からしたほうが良さそうです。
よく見るのはrails + reactという構成です。この場合、どんな計算リソースを用意してどこに何を配置するのかを整理したいと思います。

参考記事③

weseek.co.jp

railsとreactを組み合わせる方法としても構成パターンはいくつか有るみたいです。
ただ、reactもとどのつまりJavascriptなので、クライアントサイド(ブラウザ)上で動きます。
railsのアプリケーションはサーバーにあり、reactをレンダリング?したJavascriptをhtml, cssと一緒にクライアントサイドに送って、その後ユーザーの挙動によってブラウザからreact部分がサーバーにリクエストを送ってサーバーからコンテンツを取得して、随時Javascript?で反映するというのがreactの仕組みのようです。
railsとreactを分割するパターンと分割しないパターンがあるようです。

他のreactを使ったアーキテクチャも見てみましょう。

参考記事④

qiita.com

python + reactを見てみました。
これもrailsと同じ考えですね。そりゃそうだって感じですが。

reactはクライアントサイドで動くものなので、サーバーサイドからAPIを返してくれるものは別途必要になるということですよね。railsなりpythonなりgoなり。(あるいはFirebase?ここの連携イメージが掴めていませんが)
となると、Next.jsはサーバーの機能があるものということで、サーバーサイド言語が別途必要ではないということでしょうか?

参考記事⑤

hokaccha.hatenablog.com

rails + Next.jsのパターン。
サーバーの機能があるとはいいつつも、Next.jsだけでサーバーサイドを完結させるのはあまり得策では内容です。DBとのやりとりが整備されていないため結構手間になると。なので結局reactと同じようにrails部分ではAPIの提供をして、フロントの描画をNext.jsという分け方にするのが吉のようです。
ここでGraphQLをその間にかませるという方法もあるようなのですが、GraphQL、単語としては頻繁に見かけるんですが、実際なのをやるものなのかわかっていなかったので、GraphQLについても少し調べます。

参考記事⑥

circleci.com

フロントエンドがAPIサーバーからデータを取得するときに、フロントがほしい形でデータを渡してくれるためのインターフェースみたいな役割を果たす、という認識です。
これをかまさないと、毎回全データ?がサーバーサイドから返ってきてしまうのでコストになると。

そのほか参考記事

hirokikaneko.medium.com

ちょっと余談気味かつ古い記事ですが、従来の(railsのような)アプリケーション開発と、reactでの開発は頭を切り替えていかないと理解できないとのこと。reactを習得していく上でのつらみとかの雰囲気がわかりました。とはいえ、この記事から4年くらい経過しているので、今は色んな情報が溢れていて、そのあたりの概念の理解の助けになる記事は多くあるかと思います。

結論

このあたりまで自分で調べてみて、友人のフロントエンジニアに聞いてみたところ、やはりNext.jsでいいと思うとの進言をいただいたので、Next.jsで行きたいと思います。

周辺の技術はおいおい調べつつやっていきたいと思います。