- 1. learn-go-with-tests スタブ・モック
- 2. [Go / Echo] Middleware におけるエラーハンドリング時の注意点
- 3. 【初LT登壇】「sqlxからpgxへの移行を今はしない判断をするまで」の深堀りをしてみます!
- 4. 依存性逆転の原則をGolangを用いて解説(SOLID原則)
- 5. golangci-lintを使ってみる
- 6. Goのnet/httpで、ミドルウェアを書いてみる
- 7. Amazon Linux 2023にGolangをインストールする
- 8. GORMでPostgresのjsonb型を扱う
- 9. learn-go-with-tests マップ
- 10. GoのSliceとMapをforループで回すときのnilの扱いを動かしながら調べた
- 11. Goのnet/httpでサーバーのハンドラー処理を作ってみる
- 12. Goのsql.Openは必ずしも接続を確立しない
- 13. Goのスライスの挙動
- 14. Goの文法を軽く勉強したので、軽くまとめてみる
- 15. GoでJSONデータをメモリ効率よく処理する
- 16. Go言語入門 : goroutineとチャネルを使った簡単並行処理
- 17. GoのテストでDBをモックする
- 18. Goで値渡しをするかポインタ渡しをするかの基準
- 19. Goのerrors.Isとerrors.Asの使いどころ
- 20. Goのエラーチェーンでエラーが起こった流れを把握する
learn-go-with-tests スタブ・モック
# スタブ・モック
3からカウントダウンするプログラムを作成するように求められました。各数値を新しい行に表示します(1秒の間隔を置いて)、ゼロに達すると「Go!」と表示します。そして終了します。“`
3
2
1
Go!
“`これに取り組むには、Countdownという関数を作成します。この関数をmainプログラム内に配置して、次のようにします。
“`
package mainfunc main() {
Countdown()
“`
これはかなり簡単なプログラムですが、完全にテストするには、いつものように反復的、テストドリブンのアプローチを取る必要があります。反復とは、できる限り小さなステップを踏んでいることを確認することです。要件をできる限り小さくスライスして、動作するソフトウェアを使用できるようにすることは重要なスキルです。作業を分割して反復する方法は次のとおりです。
– 表示 3
– 3、2、1 を表示してGo!
– 各行の間で1秒待ちます## 最初にテストを書く
“`
func TestCountdown(t *testing.T) {
[Go / Echo] Middleware におけるエラーハンドリング時の注意点
## 前段
ミドルウェアのエラーログハンドリング周りの処理が複雑で、いくつか問題が発生していました。
その対処を行う過程で自分が得た知見を簡単にご紹介します。## ミドルウェアの処理順序
まず Echo の Middleware における注意点は、その処理順序です。仮に、A・B という Middleware があったとします。
それを、下記のように順に呼び出します。“`
echo := echo.New()
echo.Use(echo.MiddlewareFunc(middlewares.NewA()))
echo.Use(echo.MiddlewareFunc(middlewares.NewB()))
“`
そして、上記 A・B のそれぞれの Middleware の中では下記のように処理しているとします。
“`
func NewA() echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context)
【初LT登壇】「sqlxからpgxへの移行を今はしない判断をするまで」の深堀りをしてみます!
こんにちは。
株式会社HRBrainでバックエンドエンジニアをしているみつです!
この春に新卒として入社し、さまざまな経験を積む中で、「**sqlライブラリの移行**」というタスクに立ち向かう機会がありました。
[**2024.05.20にししとうLT**](https://4410.connpass.com/event/316005/)では、時間の都合上話せなかった詳細について、この記事で補足したいと思います:relaxed:
(ちなみに、ししとうLTは私にとって人生初のLT登壇でした:joy: 記事執筆時点では、社外LTに聞く側でしか参加したことがないので、もし誘っていただけたら嬉しいですw)
– [資料はこちら ▼](#資料はこちら-)
– [`sqlx`から`pgx`への移行までの話](#sqlxからpgxへの移行までの話)
– [出したかったログの種類:writing\_hand:](#出したかったログの種類writing_hand)
– [色々なGoのSQLライブラリを検討:sunny:](#色々なgoのsqlライブラリを検討sunny)
– [`pq`につい
依存性逆転の原則をGolangを用いて解説(SOLID原則)
## 目次
– [背景](#背景)
– [依存性逆転の原則(DIP)とは](#依存性逆転の原則dipとは)
– [コードを用いた説明](#コードを用いた説明golangでのmodel-view-controllerのケース)
– [従来の構成](#従来の構成)
– [依存性逆転(DIP)構成](#依存性逆転dip構成)
– [まとめ](#まとめ)
– [参考URL](#参考url)## 背景
インターフェースの意義を調べていく中でSOLID、依存性逆転の原則について理解する必要があったため、これらの調査内容をまとめる。## 依存性逆転の原則(DIP)とは
[SOLID](https://ja.wikipedia.org/wiki/SOLID)(オブジェクト指向に用いられる原則)の頭文字
S 単一責任の原則 (single-responsibility principle)
O 開放閉鎖の原則(open/closed principle)
L リスコフの置換原則(Liskov substitution principle)
I インターフェース分離の原則 (in
golangci-lintを使ってみる
## はじめに
goでプログラミングした際に、文法間違いやエラーチェックが抜けている箇所を指摘してくれるgolangci-lintを使ってみます。## golangci-lint インストール
“`zsh
brew install golangci-lint
brew upgrade golangci-lint
“`## Goを書く
“`go
package mainimport (
“net/http”
)func middleware1(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(“before middleware\n”))
next.ServeHTTP(w, r)
})
}func middleware2(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.
Goのnet/httpで、ミドルウェアを書いてみる
## はじめに
Goの標準パッケージを使ったプログラミングに慣れるために、net/httpだけでミドルウェアを書いてみました。next.ServeHTTP(w, r)の前に書くか、後に書くかで、いつ処理されるかが決まるようです。
“`go
package mainimport (
“net/http”
)func middleware1(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(“before middleware\n”))
next.ServeHTTP(w, r)
})
}func middleware2(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
next.ServeHTTP(w, r
Amazon Linux 2023にGolangをインストールする
# はじめに
英語に拒否反応持ってしまう人も多いと思いますので、自分のインストール方法をここに記載しておきます。
2024/7/1時点、現在のバージョンは`go1.22.4`です。
対象OSはAmazonlinux2023を想定しています## 1.バイナリのダウンロード
“`bash
wget https://go.dev/dl/go1.22.4.linux-amd64.tar.gz
“`
## 2.rootユーザにスイッチ
“`bash
sudo su
“`
## 3.不要なディレクトリ削除、バイナリ解凍、配置
“`bash
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.22.4.linux-amd64.tar.gz
“`
※rootで実行すること## 4.rootユーザの終了
“`
exit
“`
## 5.パスを通す(bashrcに追記)
公式だと、.profileに記載するようありますが、
個人で使うだけなのでユーザで良いという判断です。
“`bash
vim ~/.bashrc
“`
.ba
GORMでPostgresのjsonb型を扱う
GORMでPostgresのjsonb型をシンプルな実装で扱う方法についてご紹介します。
# Postgresのjsonb型
PostgresではJSONを扱うデータ型としてjson型の他にjsonb型が用意されています。jsonb型の方が下記の通り、公式でも利用が推奨されていてデータ取得時のパフォーマンスが良くなるなどのメリットが有るようです。https://www.postgresql.jp/document/16/html/datatype-json.html
> json型とjsonb型というデータ型は、ほとんど 同一の入力値セットを受け入れます。 現実的に主要な違いは効率です。 jsonデータ型は入力テキストの正確なコピーで格納し、処理関数を実行するたびに再解析する必要があります。 jsonbデータ型では、分解されたバイナリ形式で格納されます。 格納するときには変換のオーバーヘッドのため少し遅くなりますが、処理するときには、全く再解析が必要とされないので大幅に高速化されます。 また jsonb型の重要な利点はインデックスをサポートしていることです。
> 一般的に、ほ
learn-go-with-tests マップ
# マップ
配列とスライスでは、値を順番に格納する方法を見ました。 では、keyでアイテムを保存し、すばやく検索する方法を見てみましょう。マップを使用すると、辞書と同じようにアイテムを保存できます。 keyは単語、valueは定義と考えることができます。 そして、独自の辞書を構築するよりも、マップについて学ぶより良い方法は何でしょうか?
まず、辞書に定義された単語がすでにあると仮定すると、単語を検索すると、その単語の定義が返されます。
## 最初にテストを書く
まずテストを書きます。実行すると当然パスしません。
`./dictionary_test.go:8:12: undefined: Search`“`dictionary_test.go
package mainimport “testing”
func TestSearch(t *testing.T) {
dictionary := map[string]string{“test”: “this is just a test”}got := Search(dictionary, “test
GoのSliceとMapをforループで回すときのnilの扱いを動かしながら調べた
Goのfor rangeでSliceやMapをループ処理を行うことがたくさんあると思います。
rangeの対象のlengthが0やnilの場合、どのような挙動をするのかが気になったのでサンプルコードを書いて動かしてみました。
## Slice
釈迦に説法かもですが、Sliceとは可変長の配列のことで全ての要素の型は同じです。
“`go
ints := []int{1, 2, 3, 4, 5}
fmt.Println(“[]int{1, 2, 3, 4, 5}のlen:”, len(ints))
fmt.Println(“[]int{1, 2, 3, 4, 5}のrange”)
for i, v := range ints {
fmt.Println(i, v)
}
“`こんなコードを書いたときにlenは5、for文は5回繰り返します。
アウトプットは以下のようになります。
“`
[]int{1, 2, 3, 4, 5}のlen: 5
[]int{1, 2, 3, 4, 5}のrange
0 1
1 2
2 3
3 4
4 5
“`次からSli
Goのnet/httpでサーバーのハンドラー処理を作ってみる
## はじめに
net/httpパッケージを使って、サーバーのハンドラー処理を書いてみた。handler1、handler2、handler3、handler4、どれも書き方は若干違うが、最終的にhttp.Handle()が呼び出され、ルーティングが登録されるため同義となる。
http.Handle()の第2引数では、http.Handler型が指定されており、http.Handlerはインターフェイスで、ServeHTTPメソッドの実装を期待しているので、それを実装した型を入れてやると動く。
http.HandlerFunc()は、http.ResponseWriterと*http.Requestを引数に持つ関数が指定されており、実行するとhttp.HandlerインターフェイスのServeHTTPメソッドを実装した、http.HandlerFunc型になるので、それをhttp.Handle()に渡す。
“`go
package mainimport (
“net/http”
)type handler3 struct{}
func (h *handler3)
Goのsql.Openは必ずしも接続を確立しない
## はじめに
タイトルのとおり、sql.Openは必ずしも接続を確立しないようです。https://pkg.go.dev/database/sql#Open
> Open may just validate its arguments without creating a connection to the database. To verify that the data source name is valid, call DB.Ping.
DeepL翻訳
> Openは、データベースへの接続を作成せずに引数を検証するだけかもしれません。データ・ソース名が有効かどうかを確認するには、DB.Ping を呼び出します。なので、DBの接続を確実にチェックしたいなら、Ping()を使います。
ヘルスチェックするときにも使えそう。
“`go
package mainimport (
“database/sql”
“fmt”
“os”_ “github.com/go-sql-driver/mysql”
)var (
dbUser = os.Ge
Goのスライスの挙動
## はじめに
Goのスライスの挙動について調べた。容量を超える要素を追加したときは、元の容量を2倍したスライスが作られる。
元のスライスをコピーして新しいスライスが作られるため、メモリ上のアドレスが異なる。
つまり、元のスライスの分だけ、余分にメモリを消費するということ。
“`go
package mainimport “fmt”
func main() {
s1 := make([]int, 1, 5)
fmt.Println(“Len:”, len(s1), “Cap:”, cap(s1)) // Len: 1 Cap: 5
fmt.Printf(“%p\n”, s1) // 0xc00001a150// 容量を超える要素を追加
s1 = append(s1, 1)
s1 = append(s1, 2)
s1 = append(s1, 3)
s1 = append(s1, 4)
s1 = append(s1, 5)
fmt.Println(“Len:”, len(s1), “Cap:”, ca
Goの文法を軽く勉強したので、軽くまとめてみる
# はじめに
A Tour of Goで軽く文法の勉強をしたので、ここに記事として少しまとめてみようと思います。# 構文
### 型定義
JavaやC#等の静的型付け言語は
“`
型 <変数> = …
“`
というように 型名から書き始めると思います。しかし、Goでは
“`
<変数> 型
“`
と逆になっています。例えば、int型の変数xを宣言する場合
– C#
“`
int x;
“`
– Go
“`
x int
“`:::note
後ろに`;`がつきません、気をつけてください
:::### 変数定義
変数を宣言する場合は、先ほどの型宣言に加えて`var`をつける必要があります。
“`
var x int
“`:::note
もし具体的な値を設定しなければ、この場合xは0になります。
bool型の場合は、falseになります。
:::### 定数定義
javascriptと同じように`const`を定義できる。
“`
const x int = 1
“`### 関数宣言
関数は以下のように宣言します。
“`
fu
GoでJSONデータをメモリ効率よく処理する
GoでJSONを扱う場合、”encoding/json”パッケージを使います。
よく使うのは、MarshalとUnmarshalの2つですが、今回は以下のメソッドを使用していきます。
メモリに保存せずストリームとして処理する
– NewEncoder
– NewDecoder“`go
package mainimport (
“encoding/json”
“os”
)type User struct {
Name string `json:”name”`
Age int `json:”age”`
Email string `json:”email”`
}func main() {
user := User{
Name: “Test”,
Age: 25,
Email: “test@example.com”,
}file, err := os.Create(“user.json”)
if err != nil {
panic(err)
}
defer file.Close()// ストリームとし
Go言語入門 : goroutineとチャネルを使った簡単並行処理
Go言語の特徴の一つに、軽量な並行処理を簡単に実現できる「goroutine」と「チャネル」があります。本記事では、goroutineとチャネルの基本概念とその使い方について、学んだことをアウトプットしたいと思います。
# goroutineとは
goroutineは、Go言語で使われる軽量なスレッドのようなもので、並行処理を簡単に実現するための機能です。goroutineを使うと、複数の処理を同時に実行することができます。
# goroutineの基本概念
軽量な並行処理: goroutineは少ないメモリで多くの仕事を同時にこなせます。
簡単な使い方: 関数呼び出しの前に`go` キーワードを使うだけで、簡単にgoroutineをスタートできます。“`
go 関数名()
“`# 実例1: 基本的なgoroutine
以下は、goroutineを使ってメッセージを表示する簡単な例です。
※ [原神](https://genshin.hoyoverse.com/ja/home)でお馴染みの[ナヴィアさん](https://genshin.hoyoverse.com/j
GoのテストでDBをモックする
# はじめに
こんにちは、H×Hのセンリツ大好きエンジニアです。(同担OKです😉)今回はGoにおいてデータベースを扱う関数のテストを行うためにDBのモックを用意する所と、実際に使用したテストを紹介していきます!
# DBをモックしてテストする
### 使用するライブラリ
`github.com/DATA-DOG/go-sqlmock`を使用します。https://github.com/DATA-DOG/go-sqlmock
こちらは、SQLドライバのような振る舞いをしてくれるモックを生成してくれるライブラリです。
モックを使うことで、テスト用のDBを用意しなくても良くなります。### 今回テストする関数
ユーザをEmailから検索するという関数(`UserByEmail`)を用意しました。
この関数は、usersテーブルからクエリとして受け取ったEmailが存在するかチェックする関数となっています。
“` user.go
package persistenceimport (
“backend/domain/model”
“backend/domain/rep
Goで値渡しをするかポインタ渡しをするかの基準
構造体のフィールドの値を変更する必要があるなら、構造体のポインタで渡す。
そうでないなら、値で渡す。
値で渡した場合は、構造体のコピーが作られるため、元のデータが変更されない。
なので、基本的にポインタで渡しておき、フィールドのデータを書き換える必要がない場合や明確に元のデータを書き換えたくない場合には値で渡す。
“`go
package mainimport “fmt”
type mutableUser struct {
ID int
Name string
Age int
}func (u *mutableUser) SetAge(age int) {
u.Age = age
}type immutableUser struct {
ID int
Name string
Age int
}func (u immutableUser) SetAge(age int) {
u.Age = age
}func main() {
// Mutable
mutableUser := mutableUser{ID: 1, Name
Goのerrors.Isとerrors.Asの使いどころ
## errors.Is
エラーチェーンの中で、特定のエラーが存在するか確認する場合に使う。
以下の場合だと、queryDatabase関数内でErrDatabaseエラーが発生していて、それをmain関数内で存在しているか確認している。
もしqueryDatabase関数でエラーがない場合は、convertData関数内のErrConvertエラーの条件に該当する。
“`go
package mainimport (
“errors”
“fmt”
)type queryResult struct{}
// 独自エラーを定義
var (
ErrDatabase = errors.New(“database error”)
ErrConvert = errors.New(“convert error”)
)func queryDatabase() (result *queryResult, err error) {
// なにかしらの処理をしたと仮定
return result, fmt.Errorf(“query failed: %w”, ErrD
Goのエラーチェーンでエラーが起こった流れを把握する
Goにはスタックトレース機構がないので、どういう流れで処理が行われたのかが把握できない。
そのため、一番初めの呼び出し元にエラーをラップして戻す方法で、エラーの流れを把握する。
“`go
package mainimport (
“errors”
“fmt”
)type queryResult struct{}
func queryDatabase() (result *queryResult, err error) {
// なにかしらの処理をしたと仮定
// 一番最初のエラー
return result, errors.New(“database is down”)
}func fetchData() (result *queryResult, err error) {
res, err := queryDatabase()
if err != nil {
// エラーをラップして返す
return &queryResult{}, fmt.Errorf(“fetchData failed: %w”, err)
}
re