• home
  • 今年やったエンジニアリング環境の整備とか

今年やったエンジニアリング環境の整備とか

この記事はWanoアドベントカレンダーの23日目です。

俺が言うんだから23日で間違いない。

さて、今年はいっぱいGoを書いたんですが、その中でみんなで細々としたところでエンジニアリング環境を整備したりしたので、備忘録的にまとめたいと思います。

IDE

うちのチームではGoを書く上で、主にIntelliJ IDEAをメインで使っている人が多いです。
そのため、チーム内でIntelliJの設定ファイルを各プロジェクトで共有しています。

IntelliJで実行するテスト実行設定の共有

Cmd + Rで実行できるテストや実行環境の設定を共有しています。

Run/Debug ConfigurationsのShare設定をすると、設定ファイルが.idea/runConfigurations/のディレクトリにに作られるので、それをgitで管理しています。

Working directoryは自分のPC上のディレクトリが絶対パスで表示されていますが(写真だと/Users/shun/go/src/の部分)、runConfigurationsの中身は

<working_directory value="$PROJECT_DIR$/hoge_package" />

と書いてあり、プロジェクトのルートディレクトリからの相対パスで個人の環境に依存していないので、共有しても問題ありません。

また、地味にGoのテストではテスト結果をキャッシュをするので、テストによっては必要に応じてキャッシュをオフにするGOCACHE=offの環境変数も設定したりしています。

go fmtの設定の共有

Goを書くならコードフォーマットしてくれるgo fmtの設定は必須です。
IntelliJではFileWatchersというプラグインで、ファイル保存時に自動でgo fmtの実行ができます。
FileWatchersの設定は以下のようにすると環境に依存しない形でgo fmtの自動実行ができるようになります。

  • Programは$GOROOT$/bin/gofmt
  • Artgumentsは-w $FilePath$
  • Output paths to refreshは$FilePath$

CI

去年はbitbucket-pipelinesを使っていましたが、今年からAWS CodeBuildを使っています。
masterブランチ、developブランチ、プルリクエストを送っているブランチにpushがあった時に、自動でECR上にあるDockerイメージを使って、CodeBuildがテストを回してくれます。

設定した当初は、CodeBuildがbitbucketの繋ぎこみに対応しておらず、bitbucketのwebhook -> AWSのAPI Gateway -> Lambda -> CodeBuildという経路を作る必要がありましたが、今はCodeBuildの設定からbitbucketを直接繋ぎ込んで設定することができるようになっているため、現在ではAPI GatewayとLambdaの設定をする必要がありません。

そしてテストの結果はSlackで通知。

naotoが設定したなぜか煽り力の高いテスト結果通知。

プルリク

先ほどのCIと合わせて、今年はプルリクを頻繁に行うようになりました。
bitbucket上でプルリクのレビューを行なっています。

bitbucketで自分がレビュアーになっているプルリク一覧はここから見ることができます。

ちなみにリポジトリの設定で、デフォルトのレビュアーにコアメンバーを設定しておくと、いちいちプルリク時にレビュアー設定をしなくていいので楽です。

あと、本当はブランチのアクセス許可設定とか、Branching model設定とか、色々整備したいんですけど、まだそこまではできていません。

バージョン管理

これまでperlとか書いていた人が多かったので、動いているスクリプトが今の最新バージョンや!って感じだったんですけど、goだとバイナリーになっちゃうので、何もしないと動いているバイナリーがいつのバージョンかわからんということに。

なので、git tagでバージョン管理を行うとともに、ビルド時にバージョン番号をバイナリーに埋め込むことにしました。

goでのバージョン番号埋め込みは、まずmain関数で、

func main() {
...
    flag.BoolVar(&showVersion, "v", false, "show application version")
    flag.BoolVar(&showVersion, "version", false, "show application version")
    flag.Parse()

    if showVersion {
        fmt.Println("version(", version+"."+revision, ")")
        os.Exit(1)
    }
...

と書いておいた上で、ビルド時に以下を実行しています。

go install -ldflags "-X main.version=$(git describe --tags --abbrev=0) -X main.revision=$(git rev-parse --short HEAD)"  hoge-package

main.versionにgitでつけたtagのバージョンを、main.revisionにはgitのcommit idを指定しています。
これでバイナリー実行時に-vオプションをつければ、いつでもバイナリーのバージョンがわかってうれしい。

デプロイ

あんまりデプロイ周りは大したことしてなくて、デプロイ用のスクリプトを書いたぐらいです。

一応スクリプトの中では、以下のようなことをやっています。

SERVERS=`aws ec2 describe-instances --filter 'Name=tag:Application,Values=*hoge_app*' 'Name=tag:Environment,Values=production' --query 'Reservations[*].Instances[*].PublicIpAddress' --output text`
for SERVER in ${SERVERS[@]}; do
    ssh $SERVER -i $PRIVKEY -t hogehoge
    ...
done

何をやっているかというと、ec2のtagでApplicationとEnvironmentというのを作って、デプロイ時にはawsコマンドでそれを使ってサーバーのIPを検索し、デプロイしています。

ちなみに、Applicationタグのvaluesが*hoge*とワイルドカードが付いているのは、1つのec2インスタンスに複数アプリケーションがある場合に、ApplicationタグのValuesをhoge_app,fuga_app,piyo_appとカンマ区切りの文字列にしているからです。

終わりに

以上、今年やったことはこんな感じです。

この中で一番やってよかったのは、プルリクですね。
お互いプルリクで自分のコードを見せ合うようになったので、どういうコードが良いコードなのかの共通認識がチーム内で醸成されてきたと感じます。
(そして過去の自分のコードについて悪態をつくのも増えてきたと言うw)

あと、まー、やっぱCIはいいですね。
テストが動かないとCIが怒ってくれるので、おかげですぐに自分のコードのミスに気づけます。
自動テスト超大事。

みんなテストを書いていこう。