Goでよく使う（ことになるであろう）標準パッケージ

## はじめに
私が担当しているプロダクトでは、開発言語としてGoを採用しています。

開発は2023年から開始していますが、まだ規模は大きくありません[^1]。
まだ大規模なコードになっていないからこそ、現時点で利用している標準パッケージはどのような製品でも利用する頻度が高くなると考えられます。

そこで、Goに興味を持ち始めた方や、Goの採用を検討している方に向けて参考になればとおもい、importしているパッケージの情報を紹介しようとおもいます。


## 開発しているプロダクトの処理内容
担当しているプロダクトの利用者は主に以下の２とおりです。
　・弊社製品[^2]のサポートデスクの担当者
　・弊社製品の導入を担当してくれるパートナー企業様の担当者


現在開発しているプロダクトは、弊社製品の製品ドキュメントや過去のサポートデスクへのお問合せ内容を横断して検索できる全文検索システムです。
また、RAG（Retrieval-Augmented Generation）を利用して、お問合せの回答を自動作成する機能を提供しています。

Goで書いている処理は以下のとおりです。
- サポートデスクのシステムからチケット情報を取得しDBに格納する
- DBに登録した過去問合せの情報とAIサービスを利用して、パートナー様に公開可能な文章を自動作成する
- 自動作成した情報の編集／最終確認する管理画面
- 製品ドキュメントのテキスト情報をDBに格納する
- 過去問合せと製品ドキュメントを利用して、全文検索とRAGを利用した回答作成機能を提供するWebAPI[^3]


## よくつかう標準パッケージ Top 5

利用している標準パッケージの一覧は、この記事の最後にまとめます。
ここでは、importしている回数Top5のパッケージについて、主な利用方法を紹介します。

### 第１位「fmt」

fmtと言えば、fmt.Println()による標準出力です。プログラミングの入門「Hello World」でも使うとおもいます。
私がfmtを使用する主な用途はエラー処理です。

例えば、何らかのエラー情報を利用して新たなerrorを生成する場合、以下のようなコードを書きます。

```go
result, err := SampleFunc()
if err != nil {
	return fmt.Errorf("my error message: %v", err)
}
```

エラー処理は上記のコードだけで語れるほど浅い分野ではありません。
メッセージに埋め込む情報やメッセージのフォーマットなど、エラー処理で考えることは色々あります。
fmtパッケージでできることを把握することで、エラー処理の設計がより具体的にイメージできるようになるかもしれません。


### 第２位「os」

osパッケージは、主に以下の処理で利用しています。
- ファイル入出力
- os.Exitでプログラムを終了する（バッチ処理）

ファイル入出力処理もよく書く処理の一つです。
ファイルの入出力の処理は共通処理にまとめることが多いとおもいます。
私たちのコードには、まだまだ冗長な部分が多く残っているためosパッケージの登場回数が多くなっている側面がありそうです。

例えば、ファイルの読み込み処理は以下のように書きます。

```go
func ReadAll(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, fmt.Errorf("failed to open file : %v", err)
	}
	defer file.Close()

	data, err := io.ReadAll(file)
	if err != nil {
		return nil, fmt.Errorf("failed to read file : %v", err)
	}
	return data, nil
}
```

上記のように読み込んだ[]byteをフォーマットに合わせてDecodeしたりします。


### 第３位「encoding/json」

昨今のWeb APIは、リクエストボディやレスポンスボディにjsonを使用することが多くあるとおもいます。
私が担当しているプログラムも、Web APIはもちろん、ファイルフォーマットにもjsonを利用しています。

個人的には、標準機能にjson関連の処理が実装されている点はGoを採用する理由の一つに挙げられると考えています。
よく使う処理ほど、プログラミング言語の標準機能として実装されていて欲しいと考えています。

第２位のosパッケージで紹介したサンプルコード「ReadAll」を利用して、jsonファイルを読み込む例を書いてみます。

```go
// このstructにファイルの内容を読み込みます。
// goはstructのフィールドにメタ情報（struct tag）を記述することができます。
// この例では、Value01というフィールドに、jsonファイルのval01というフィールドを対応させています。
type SampleStruct struct {
	Value01 string `json:"val01"`
}

func main() {
	data := &SampleStruct{}
	err := file.ReadJSON("sample.json", data)
	if err != nil {
		// エラー処理
	}
	fmt.Println(data.Value01) // jsonファイルの内容表示
}

// jsonファイル読み込み
// 引数resultは読み込んだ内容を格納するstructを想定しています。
func ReadJSON(path string, result interface{}) error {
	// ReadAllはosパッケージのコード例を参照してください。
	b, err := ReadAll(path)
	if err != nil {
		return err
	}

	decoder := json.NewDecoder(bytes.NewReader(b))
	decoder.UseNumber()
	err = decoder.Decode(result)
	if err != nil {
		return fmt.Errorf("failed to decode file : %v", err)
	}

	return nil
}
```

### 第４位「time」

日付や時間に関する処理もシステムにはつきものです。
今回は、DBのレコードに「レコード作成日時」と「レコード更新日時」のカラムを定義しています。
このカラムの値は、システムを操作したときの時間やファイルに記述されている時間を登録しています。
このときにtimeパッケージを使用しています。

例えば、現在のローカル時刻を取得する場合は、以下のように記述します。

```go
now := time.Now()
```

例えば、日時を表す文字列をTime型に変換する場合は、以下のように記述します。

```go
updateAt, err := time.Parse(time.RFC3339, "2024-01-02T03:04:05Z09:00")
```


### 第５位「strings」

stringsパッケージは、文字列操作を提供してくれるパッケージです。
私が担当しているコードでは、以下のFunctionを利用しています。
Function名からどのような処理かは想像がつく程度におなじみの機能だとおもいます。

- strings.Contains
- strings.HasPrefix
- strings.Index
- strings.Join
- strings.LastIndex
- strings.NewReader
- strings.Replace
- strings.ReplaceAll
- strings.Split
- strings.Trim
- strings.TrimLeft
- strings.TrimPrefix
- strings.TrimRight
- strings.TrimSpace
- strings.TrimSuffix


### 次点
Top 5 からは外れましたが、以下のパッケージもよく使うという印象があります。

- path/filepath
ファイルパスを構築するときに使います。OSごとのパスセパレータの違いを吸収してくれます。

- strconv
文字列と数値の変換に使います。


### まとめ

よく使う処理は共通処理にまとめることが多いため、importしている回数が使用頻度ではないという点は承知しています。
例えば「net/http」や「database/sql」も処理としてはよく使いますが、処理を共通化しているためimportしている回数は多くありませんでした。

しかし、今回紹介したパッケージはあらゆるシステムで利用すると言っても過言ではないとおもいます（言いすぎかもしれない）。
Goに興味を持たれた方には、一度チェックしてみることを自信をもってお勧めすることができます。

最後に今回調べた範囲内で利用しているGoの標準パッケージとimportしている回数の一覧を載せておきます。

|パッケージ|回数|
|:--------|---:|
|fmt|43|
|os|36|
|encoding/json|26|
|time|19|
|strings|18|
|path/filepath|11|
|strconv|11|
|bytes|10|
|flag|8|
|io|8|
|net/http|8|
|context|5|
|errors|5|
|regexp|4|
|sync|4|
|encoding/csv|3|
|log/slog|3|
|slices|3|
|sort|3|
|database/sql|2|
|text/template|2|
|bufio|1|
|encoding/base64|1|
|os/exec|1|
|reflect|1|
|unicode/utf8|1|


[^1]: 2024年11月に正式稼働を開始しました。
その区切りとしてコードを見直しながら今回の記事を書いています。

[^2]: mcframe 7
SCMと原価管理のパッケージシステム。

[^3]: 全文検索にはElasticSearchを利用しています。
RAGを利用したAI機能は、Azure OpenAI Serviceを利用しています。