見出し画像

GWで作成したシステムでの備忘録

背景

GW中にシステムについて勉強しました。バックエンドAPIの作りとDB、フロントエンドについて学習したのでその時に理解した事や悩んだ事について記載します。

構成

バックエンド

  • golang: v1.21

  • gin:v1.9.1

データベース

  • postgres: v15

フロントエンド

  • vue3.js

  • typescript

難しかったこと

バックエンド

  • バックエンドAPIから全然データ作れなくておかしいなーって思ってたけど、よくよく考えてみたらSQLのデータを読み取るための型をずっとSQL実行の時に利用していて永遠にデータ取れなかったこと

    • SQL文字列を実行する時に渡すデータ型とSQLの結果をスキャンする時のデータ型は別物

// pgtypeでのSQLのデータを取得する時の定義の仕方
type UserData struct {
	Id        pgtype.UUID
	FirstName pgtype.Text
	LastName  pgtype.Text
	Email     pgtype.Text
}

// gin側でエンドポイントに渡された値を取得する時の定義の仕方
type InputUserData struct {
	Id        string `form:"hotel_id"`
	FirstName string `form:"first_name" binding:"required"`
	LastName  string `form:"last_name" binding:"required"`
	Email     string `form:"email" binding:"required"`
}

pool.query(ctx,sqlstatemant,InputUserData.FirstName)
pool.Scan(ctx,sqlstatemant,UserData.FirstName)
  • リクエストデータを取得するための文字列の設定を間違えてバリデーション用のキーが効いていなかった事

    • ずっとform用の構造体の形がkey:valueで複数設定するのに、最初のkey:valueのvalueが閉じてなくて残りが全部ただの文字列になってた

// ""がvalue の終わりに付与されていなくて、bindingがずっと設定されていなかった。
type InputUserData struct {
	FirstName string `form:"first_name binding:required"`
	LastName  string `form:"last_name binding:required"`
	Email     string `form:"email binding:required"`
}

フロントエンド

フロントエンドでvue3.jsでtailwind cssを設定しようとしたのだが、初期設定に苦労してなかなか最初の反映までに時間が掛かった。

tailwind cssの設定の仕方

前提

  • vite:4.5.3

  • typescript:5.1.6

  • vue3.js:3.4.26

  • engin

    • node 18.17 >=

    • pnpm 8.7.4 >=

基本的には公式の作り方を参考にすれば問題ないのですが私の環境では、jsではなくタイプスクリプトを利用していたのでそのままだと上手く設定できなかった為ここに記載します

install tailwind css

pnpm install -D tailwindcss postcss autoprefixer
pnpm tailwindcss init

Add Tailwind to your PostCSS configuration
ここで、設定しているのが、公式ではjsファイルですがCommonjsを示す.cjs
拡張子で保存します

// postcss.config.cjs
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  }
}

Configure your template paths
ここでも同じく、ファイルの拡張子は.cjsにします。
tailwindの設定を反映させるファイルをcontentに指定します。公式ではjsとhtmlのみになっているので、vueやreactを使用しているユーザーはtsx,jsx,vueの文字列を追加してください

// tailwind.cofig.cjs
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{html,js,ts,jsx,tsx,vue}"],
  theme: {
    extend: {},
  },
  plugins: [],
}

Add the Tailwind directives to your CSS
ここでは自分のプロジェクトで利用しているmain.cssファイルに対して以下の設定を追加してください。なお初期設定をしているvueユーザーはproject/src/assets/main.cssがメインCSSファイルに該当します。

// project/src/assets/main.cs
@tailwind base;
@tailwind components;
@tailwind utilities;

Start your build process

// 開発モードを実行する
pnpm run dev

Start using Tailwind in your HTML
vueユーザーは自分のvueコンポーネントに対して、classタグを作成し設定すれば表示をすることができます。

<script>
</script>

<template>
    <img :src="image" :alt="image description" @error="handleErrorOfImage" class="rounded-md w-16">
</template>

<style>
</style>
vueでのtailwind css が設定されている状態

気づいた事

フロントエンド

フロントエンドの重要な考え方、コアとなる考え方は受け取ったデータをどの様にしてフロントエンド側で保持するか、ユーザーに見せる時のデータは保持しているデータから何を表示させるのかという部分。

バックエンド

  • APIHandlerを一つのHandlerに依存させていたけど、ハンドラーの構造体は一つにまとめるのではなくて、目的に応じて分解してあげた方がやっぱり良さそう

// APIハンドラーの定義
type ApiHandler struct {
	Conn      *pgxpool.Pool
	ginCtx    gin.Context
	ServerCtx context.Context
}

// 上記のAPIハンドラーに対して、それぞれのAPIのメソッドを生やして作ってしまったが故に
依存先が20個以上になってしまい、簡単に変更するのが難しくなってしまった。
やるなら、一番大きいAPIHandlerに対して、それぞれの用途に合わせたハンドラーを作成した方がいいかも
type APIHandler struct {
HotelHandler
BookingHandler
}
  • アプリケーションコードでSQLの読み取りに失敗した時のエラー文言にめちゃ助けられた

    • 下記は、SQL文で受け取る6個の引数の定義に対して、sqlクライアント側に渡している引数が8個渡していて、エラーになっている時の文

number of field descriptions must equal number of destinations, got 8 and 6

データベース

  • データベースの列名変えると、影響範囲が大きいから既存のデータベースに対して名前を変えるというのは保守、運用においてあまり得策じゃなさそう

psqlクライアントで新しく覚えたコマンド

\d 任意のテーブル

このコマンドを実行することで任意のテーブルがどのような構成になっているのかを一発で理解することができる

\d 任意のテーブルの表示結果

テーブルの操作

テーブルに新しく列を追加する

ALTER TABLE 任意のテーブル ADD COLUMN 列の名前 型;

テーブルの行を削除する

ALTER TABLE 任意のテーブル DROP COLUMN 列の名前 型;

テーブルのデータを変更する

データを更新した後の値を取得したい時は、最後にRETURNINGを追加するとできます。これを付与しておく事でユーザーデータを更新した時に更新後のデータを返却するので、フロントから再度APIに対して問い合わせをしなくて良いという利点があります。

UPDATE products SET price = 10 WHERE price = 5 RETURNING price;

テーブルのデータを削除する

データを削除した後にRETURINING句を挿入しておく事で、行を削除されたかを確認できます。

DELETE FROM products WHERE price = 10 RETURNING *;

その他

開発の速度をあげる為に、正規表現上手く使える様になると、複数出ている箇所を一気に置換できるというメリットがあるからできるようになるべきだと思った。

  • 理解していたつもりだったけど、改めて理解できたAPIテストの重要性

    • 一気に作り上げた結果途中でリクエスト飛ばしても上手く値が取得できないタイミングがあってイライラしたからAPIテスト導入したらどこが壊れているかすぐ分かって開発しやすくなった

    • 500エラーになる。定義しているはずなのに404エラーになる等々

  • DBに依存するテストであっても、SQL書いたら一先ずそのコードに対してテストを実施した方が後々助かることになる

    • SQL の実行がそもそも正しくできているのか、エラーになっていないかを事前に確認しておかないと、バックエンドで定義した関数が間違っているのか、API側のハンドラーか間違っているのか、APIの入力値が間違っているのかとか判断に困る

ベテランエンジニアからFBもらった考え方について

社内のベテランエンジニアからもらったFB

どんなデータ構造にするかを考える時はどんなトラブルが発生するかを想定すると良い。
このデータをどういう風に表現するとユーザーは嬉しいかを考える。
プランデータの表示するなら、予約できる人数だったりバックエンドから送る時のフロントエンドで表示するべきデータの構造だったりを意識するとよい。

全てのデータについてはcreated_atのデータを作る必要がある。
DB側で勝手に作成される様に設定することも出来る。
このデータがあることで作成された日で検索することができる。

参照


この記事が気に入ったらサポートをしてみませんか?