新規プロジェクトで得たgolangの知見
パッケージ管理周りの情報が錯綜としている。
以下の記事が詳しい。
個人的に注意すべきは
- envは別にいじらなくても大丈夫
-
go get
は使わない。大体、go mod tidy
で事足りる - ソースではつかはないがインストールしたい開発ツールとかは
go install
を使う。この時にバージョン指定は必須。 - マルチモジュールだとvscodeの拡張機能がうまく動かないことがあるので、go.modがあるフォルダを開くと動く。
golangはクラスがないし、パッケージレベルでのアクセス制御がないのでどのメンバを公開して、非公開にすればいいのかはじめ分からなかった。
これまではクラスのインターフェースになるメンバだけ公開して、内部の実装は隠していた。
ただこれと考え方は一緒で、パッケージのインターフェースになるメンバだけ公開すればよかった。
なんで混乱したかというと、アーキテクチャとかよく分からずに全部同じパッケージに突っ込んでいたから。
これまでフレームワークに乗っかっていただけなので、フレームワークなしのgolangを使い始めて、パッケージの切り方がわからなかった。
おかげでDDDとかレイヤードアーキテクチャについて調べるようになり、パッケージ間の依存についての知見が増えた。ほんの触りしか理解できてないが
標準でフォーマッタが用意されていていい。
go fmt
言語仕様がシンプルで冗長だが何書いてあるかはわかりやすいし、標準ライブラリとかもそんな分量ないのでAPI仕様書とソース読めば大体解決する。
ローカル環境に依存しないでいいようにDocker + Remote Container(VSCode)を使って環境を構築した。
また、いちいちビルドしなくていいようにライブリロードライブラリのairを使っている。
素の環境じゃないのでデバッガ(delve)の設定方法がわからず、printデバッグを強いられている...
誰か助けて
ロギングのライブラリがいくつかあるが、logrusとzapのどちらかにしようと思っている。
logrusは枯れていて安定している。現在メンテナンスモードでもう新規機能の開発はしないみたい。
zapはlogrusより新しくて早いみたい。
ログをltsv形式で出力したいがどちらも、デフォルトでは対応してないみたいなので自分でカスタムしないといけないが、どうやらlogrusの根本的な問題でltsvで出力するとログのカラムの順番が常に同じとは限らなくなるみたいで微妙。。
zapもいけるみたいだけど、logrusよりカスタムが複雑。。
多分zap使うけど面倒くさいから公式でサポートして欲しいという気持ち
goはクラスはないがインターフェースはある。
インターフェースはrubyと同じでダックタイピング。
クラスがないとかダックタイピングにしてるとか、goの思想みたいなのを感じるがオブジェクト指向に造詣が深くないので理由はちゃんと理解してない。
goでシングルトン作るときは、javaとかとは違ってグローバル宣言時に初期化したり、init関数を使うのがいいみたい。
例外がなくて、エラーハンドリングが特殊。
goの関数は多値を返せるので、その時にエラーを返してくる。
hoge, err := fuga()
if err != nil {
// エラー処理
}
みたいな処理がかなり出てくる。
githubのリポジトリをモジュールとしてインストールできるが、プライベートリポジトリをインストールしてくる時は少し面倒。
以下の型の変数はnil
を値に取ることができる。
- ポインタ型
- 関数型
- スライス
- チャネル
- マップ
- インターフェース型
基本的にnilはポインタがないことを意味している。(関数型もスライスも関数やスライスの実態があるアドレスへのポインタを保持している)
ただ、この中でインターフェース型だけ特殊で、そのせいでハマりやすい。
インターフェース型自体は、振る舞いだけ定義してあって、内部にどんなデータを持つのかは定義していないので、コンパイル時にはどんな型のデータが入ってくるかわからず、動的に決まる。
そして、インターフェース型の値は動的な型と動的な値という二つの構成要素を持つ。
続く
ライブラリ等のインターフェースや構造体に新しいメソッドを生やしたい場合は、新しいインターフェースや構造体を作成し、委譲をつかうことで実現できる。
nullが入るDBのカラムの値を取得する時
timeパッケージでは日時フォーマットの指定の仕方が独特。
2006/01/02 15:04:05
のような形式で指定する。
この時にちゃんと年は2006年で月は1月にしないとおかしくなる。2007年とかじゃだめ。
自分は時間を15時ではなく3時にしていて、日時が12時間ずれて気づくのに結構時間がかかった。
最初ロケールのせいかと疑った。ロケールも環境によってはAsia/Tokyo
が設定されていなことがあるらしく、気をつけるポイント。
testfixturesでDBのテストをするときはDB名の末尾に_test
がついてないとエラーになる。
どこにも書かれてないのでハマった。
レイヤードアーキテクチャを使っていて、contextを上のレイヤから下のレイヤに渡すとき、キーをどのレイヤに置けばいいのか迷った。
レイヤを横断的に使うものはルートディレクトリに新しくフォルダを切って、そこに入れるようにした。
ロガーもここに入れることにした。
cのライブラリを使っていて、ビルドすると自動的に動的リンクになる。
ただ、ビルドした環境のglibcのバージョンが、実行する環境のglibcのバージョンより新しい場合、以下のようなエラーが出る。
./main: /lib64/libm.so.6: version `GLIBC_2.29' not found (required by ./main)
ググるとビルド時に CGO_ENABLED=0
を付ければいいみたいな記事が出るが、それはcライブラリを使っていない場合だけで、使っている場合ビルドできない。(当たり前)
libc6=glibc
sqlboilerでテーブルからモデルを生成するときに、複数形でないが最後にs
がつくテーブルのモデルがsが削除されてしまう。
例えば、テーブル名がflops(=Floating-point Operations Per Secondの略)の場合、生成されるモデルはflopになる。
この場合tomlに以下のような設定を書く。
[aliases.tables.flops]
up_plural = "Flopses"
up_singular = "Flops"
down_plural = "flopses"
down_singular = "flops"
REAMEに書かれてあるが、どう設定すればいいのか分かりづらく結構時間を食った。
PR出してみようかな。