Creatodonをv3.4.6からv4.0.2へのアップデートした

はじめに

これは僕が管理しているCreatodonというMastodonのサーバーの移管とアップデートを行ったときの備忘録になります。 一部正確な情報ではないかもしれませんのでご了承ください。

経緯

前回のCreatodonアップデートの記事から一年とちょっと経ち、Fediverse界隈がにわかににぎやかになってきてました。 特にTwitterの買収騒動でのFediverseへの移住(おもにMastodonなどへの)が増え、連合するサーバーの数も徐々に増え始めており「そろそろメンテナンスしないとな」と思い、ガっとアップデートを進めることにしました。

環境

なお、Creatodonの環境としては以下のようになっています - Ubuntu 20.04 - Ruby 2.6 - Node.js v12 - PostgreSQL 12 - Redis 5

この環境でDockerを使わずに運用しています。

やったこと

リリースノートの確認

まずはv3.4.6以降のリリースノートを確認することにしました。

v3.4.6からv4.0.2までのリリースノート確認していくと、v3.5.2のリリースノートの部分にDBへのマイグレーションについての記載があるのが確認できました

github.com

それ以外の部分ではDBへのマイグレーションについての記載はなく、アップデートに関しての大きな注意点になりそうな箇所はないことがわかりました。 あとはNode.jsの最低バージョンなどの変更点があることを確認。

リリースノートとアップデート前のCreatodonの環境などを鑑みると以下の手順でアップデートで必要そうだとわかりました。 - Rubyなどのバージョンを上げる - DBへのマイグレーションをリリースノート記載の通りに対応

DBのバックアップ

DBへのマイグレーションを実行するので最悪の場合に備えてバックアップを取得します。

バックアップ自体は pg_dumpを使って以下のように実行しました。

sudo su - postgres
pg_dump mastodon > dump.sql

Rubyのバージョンアップ

次に使用するRubyのバージョンを上げました。

Mastodonの場合は.ruby-versionに記載されているバージョンのRubyを使うので、そちらを以下のコミットで修正。

github.com

ここでGemfileをちゃんと確認しておらず、3.1.2が使えると思い込んでしまったのが良くなかったですね......。

このあとbundle installを実行した際にエラーになり気付いて、以下のコミットで修正しています。

github.com

この段階で3.0.4がインストールされていない場合は以下のコマンドでインストールしましょう。

rbenv install 3.0.4

Node.jsのバージョンアップ

次にNode.jsのバージョンを上げました。

一旦はnvmを使ってバージョンを上げたんですが、Streaming周りが不安定になっていました。

そこで以下の記事を参考にnをインストールし、Node.jsのバージョンをv18系列まで上げました。

zenn.dev

マイグレーションの実行

RubyやNode.jsのアップデートなどが完了したのでマイグレーションの実行を行いました。 おそらく今回のアップデートで一番気を使った箇所ですね。

リリースノートの内容に合わせて、まずはSKIP_POST_DEPLOYMENT_MIGRATIONS=trueを付けた状態でマイグレーションを実行しました。

SKIP_POST_DEPLOYMENT_MIGRATIONS=true RAILS_ENV=production bundle exec rails db:migrate

かなり長いマイグレーションなので、コーヒーでも飲みながらのんびり待つと良いかもです。

マイグレーションが完了すると次にアセットのビルドを行います。

RAILS_ENV=production bundle exec rails assets:precompile

が、アセットのビルドは失敗。 原因としてはCreatodonで導入している独自テーマのscss周りのimportが最新のMastodonのテーマとそろっていないからでした。

そこで随時ビルドしつつ不要なimportを削除して回り、最終的にビルドできるようにしました。 一旦はビルドできてますが、独自テーマ自体のレイアウト調整などはまだ完了していないので今後折を見て直しておこうと思います。

アセットのビルドが完了したので以下のコマンドでMastodonの各サービスを再起動します。

sudo systemctl restart mastodon-web
sudo systemctl restart mastodon-streaming
sudo systemctl restart mastodon-sidekiq

各サービスが再起動した後、以下のコマンドで再度マイグレーションを実行します。

RAILS_ENV=production bundle exec rails db:migrate

これでマイグレーション周りの対応は完了です。

Sidekiq周りの設定修正

次に、Sidekiq周りの設定を修正します。

元々Creatodonでは以下のような設定でSidekiqを起動していました。

bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push -q scheduler

ただこのままだとv4.0.0以降ではうまく連合TLなどが動作しなくなる可能性があります。

ここら辺はアップデートの作業中に気付いたんですが、v4.0.0のリリースノートにingressキューを追加する必要がある旨の記載がありました。

Requires review of Sidekiq queues in some setups (new queue: ingress)

github.com

なので以下のようにSidekiqの起動処理を修正して対応しました。

bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push -q ingress -q scheduler

ここまでの対応でアップデートは完了です。

追加の対応

メール配送&ポート周りの設定修正

CreatodonではMailGunを使ってメールの配送などをしていたんですが、たまに配送できていないことがあったので対応しました。

具体的にはメール送信で利用しているMailGunのAPIキーなどを新しいものに差し替え。 またその最中に誤ってポートを閉じたりしたので、その辺も修正しました。

DeepLでの翻訳機能の導入

追加でDeepLでの翻訳機能なども導入。

以下の記事を参考にDeepL APIの認証キーを発行。

qiita.com

あとは .env.productionに以下のように発行した認証キーを環境変数として追加し、各サービスを再起動しました。

DEEPL_API_KEY=<発行した認証キー>

ElasticSearchの導入

Creatodonではサーバーの移管前まではElasticSearchを使っていたんですが、移行に際して廃止していました。 今回のアップデートに合わせて再度有効にしました。

公式の以下のドキュメントを参考にElasticSearchをインストールしました。

docs.joinmastodon.org

元々導入していたので.env.productionにはElasticSearch用のポート設定などはあり、その辺は特に設定せずに済みました。

あとは以下のコマンドを実行して各サービスを再起動し、

sudo systemctl restart mastodon-sidekiq
sudo systemctl reload mastodon-web

以下のコマンドで検索用のインデックスを生成してElasticSearchの導入は完了です。

RAILS_ENV=production bin/tootctl search deploy

おわりに

色々と立て込んでいてアップデートができていなかったので追加対応も含めると結構な作業量になってしまった感。 今後はできるだけこまめに追従していきたいですね......。

gqlgenでのgoroutine leakを解消した

はじめに

この記事は、仕事で使っているgqlgenというGo製のGraphQLサーバーを生成するツールで起きていたgoroutine leakを解消した時のまとめです

 

起きたこと

GraphQLのSubscriptionを使った機能(リアルタイム性のある機能)をリリースした直後からメモリリークで本番環境のコンテナが死ぬという現象が起きました。

 

何人かでログを漁ってみたところ、どうやらgoroutineが正常に終了していないままleakしているらしいことが判明(ログなどで本番環境のgoroutine数が異様に増えていたため)

 

やったこと

まず計測用に埋め込んでいたpprofやPrometheusのエンドポイントを有効にし、ローカル環境下でgoroutineが増大しているかを計測しました

 

計測には以下のライブラリを使用しました。

github.com

github.com

 

 

すると、Subscriptionを使った機能を使用した際に、goroutineが増加しているのが確認できました。

 

次に実装の問題なのかライブラリの問題なのかを切り分けることにし、実装側の調査を進めました。

新規で追加されているコード内で数か所goroutineを使っている箇所はありましたが、計測された結果ほど増加している感じではなかったためgqlgen側に問題がありそうと判断。

 

そこでIssueを漁ってみたところ以下のIssueが見つかりました。

github.com

 

GraphQLのSubscriptionは実装としてWebsocketを使っており、gqlgenではWebsocketのコネクションが接続された際にgoroutineを生成しているようです。

 

が、Websocketのコネクションが切れた際に生成されたgorutineが正しく終了しないコードになっているため最終的にgorutine leakが発生するということのようです。

 

修正状況などを確認すると以下のPRで修正されており、v0.17.6で修正が反映されえていることが判明しました

github.com

 

github.com

 

そこで現在使用しているgqlgenのバージョンを確認し、アップデート対応を行いました。

これで大幅にgoroutine数が削減され、leakしなくなりました。

 

解消したが......

が、その後数日様子を見ていると緩やかではありますがメモリの使用量が増大しており、コンテナが落ちていることが判明。

 

ローカル環境下でpprofを使い、gorutine数を確認してみたところ僅かにgoroutineが増えていました。

 

ただ今回はどのAPIを呼び出しても増加しており、その増加量も数件程度。

なので、ライブラリ側というよりはこちらで実装した側の問題の可能性がありそうでした。

 

pprofとログ埋め込みを併用しつつ、実装を確認したところ別で使用しているRedisクライアントがgoroutineを生成していることがわかりました。

さらに実装を追うと、ミドルウェア層にある実装で都度Redisクライアントが生成されており、その影響でgorutine数が増大しているようでした。

 

そこでRedisクライアントを一度だけ生成するように実装を変え、最終的な決着をつけました

おわりに

 

goroutine leakやメモリリークなどはまず計測することから始めるとよいなと再認識。

あとpprofでのgorutine数確認とかが体験が非常に良かった

 

Hamada.rb #34 & Ruby Hacking Challenge in Hamada.rb を開催した

毎月定例のHamada.rbとRuby Hacking Challenge in Hamada.rbを9/20に開催してきた

この記事はその振り返りです

 

Rubyのビルド

今回Ruby Hacking Challenge初参加の方が何人おり、rubyhackchallengeのチュートリアル進めてて、依存関係でビルド出来なかったので対応したりしてました。


で、ビルド出来なかった原因はlibyaml(3.2.0-preview1以降のmasterではlibyamlが同梱されなくなっており、libyamlを入れないとビルドできない)だったので、libyamlをインストールして無事ビルドできました。やったね!

 

ちなみにその後イベント中にPR出されてて非常に良かった!

github.com

 

CRubyのことを知るファーストステップ

「CRubyの実装とかを知るにあたってどんなステップで行けばいいか?」という質問が出たので僕がどう知っていったかを話してました。

 

僕の場合は「Rubyソースコード完全解説」=> 「言語のしくみ」=>「Rubyのしくみ」の順でCRubyの実装とかプログラミング言語の実装とかを知っていった感じでした。

 

i.loveruby.net

www.amazon.co.jp

www.amazon.co.jp

 

あとHamada.rbの時には忘れてたんですが、CRubyで公開されているC APIとか使って

C++の拡張ライブラリとか書いてたみたいです

 

github.com

 

なので、その時にC APIなどに触れつつCRuby内部のコードを知れたのはあるかも

parse.yの話

「parse.yは魔界」とか拡張BNF記法の話とかしつつ、「parse.yの文法パターンとかはRubyソースコード完全解説を読むと良いよ」とオススメしたりしてました

 

あとは最近投げたPRとかを例に挙げつつ、軽くBNF記法の話とかしました

github.com

 

Rubyでのベンチマーク

CRuby向けのPRの話でベンチマークとかの話が出たので

 

make benchmark/benchmark.yml -e BENCH_RUBY="../install/bin/ruby" -e COMPARE_RUBY="~/.rbenv/shims/ruby"

 

とかでベンチマーク取れるのを共有したりしてました。

 

あと、ベンチマーク結果の原因について推察したりしてました(が、結局原因らしきものは明確に突き止められなかったので残念......)

 

その他CRuby関連の情報収集など

CRuby関連の情報収集とかで助かるブログとか紹介しました

github.com

 

ruby-trunk-changes.hatenablog.com

 

secret-garden.hatenablog.com

 

この辺日頃から見ておくと色々知見が得られるのでオススメ

 

次回

次回は10/18(火)にやります!!

hamadarb.connpass.com

hamadarb.connpass.com

 

そういえば

Hamada.rb始めてから丸三年たってました!

hamadarb.connpass.com

 

Ruby Hacking Challenge in Hamada.rbももうすぐ三年経ちそう!

hamadarb.connpass.com

RubyのアプリケーションをPR単位でテストできるようにしてみた

はじめに

RubyのアプリケーションをPR単位でテストできるようにしてみた記事です。
仕事でRubyを使っていて「PR単位で気軽にテスト環境を作りたいなぁ」という人向けの内容です。

背景など

元々仕事で

  • 複数のプロジェクトが同時並行で進んでいる
  • 単一のステージング環境を使い、テストをしている
  • そのためプロジェクトがリリースされるまで、別のプロジェクトの機能がステージング環境でテストできない

という状況が発生しており、新機能リリース時のリードタイムが発生しやすいという課題を抱えていました。
また僕自身も直近ではリリースマネージャ的な動きをしていたこともあり、この状況をどうにかしたいという思いがありました。

そんな時、メルカリから公開されたKubetempuraの「PR単位でテスト環境を構築する」という考えを知り、「この方法で何とかできないだろうか?」と対応方法を考え始めた感じですね

engineering.mercari.com

ただ、

  • 僕のk8sなどへのまだ理解が浅いこと
  • 現状の環境に追加するにはKubetempuraは規模が大きすぎるかもしれない
  • 実際に運用が回るのかスモールスタートで検証したい

というところもあり、Kubetempura導入までは至っていませんでした。

そんな中、個人的な興味から試していたAppRunnerがテスト環境として使えるのではないかと思い始め

gamelinks007.hatenablog.com

色々と試行錯誤してみたところ、以下のようにPR単位でテスト環境を構築できるものができました。

github.com

作ったもの

作ったものとしては以下です。

github.com

シンプルなSinatraのアプリケーションをTerraform/GitHub Actionsを使うことでAWS上にテスト環境を自動で構築できるようにしています。
まだREADMEなどはまだ整備できていませんが、ForkしてAWS周りの認証キーなどをセットすれば動かせると思います。

やったこと

先日公開した以下の記事で作成したTerraformをもとに最低限(AppRunner/IAM/ECRまわり)の環境を構築できるコードを書き、

github.com

以下のようなシンプルなSinatraのWebアプリケーションを作成しています。
(RubySinatraを使っているのは一番使い慣れた言語であることと、テストのための環境構築が楽だったためです)

require 'sinatra'

configure do
  set :bind, '0.0.0.0'
end

get '/' do
  'Hello world!'
end

get '/halo_infinite' do
  'HALO Infinite'
end

get '/halo_2' do
  'HALO 2'
end

それを以下のようにPRが作成されたタイミングでテスト環境を構築するようにしました。

name: 'Create staging with pull request'

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest

    defaults:
      run:
        shell: bash

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure aws credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v1
        with:
          terraform_version: 1.1.9

      - name: Init
        run: terraform init
        working-directory: infra
      
      - name: Get
        run: terraform get
        working-directory: infra

      - name: Apply
        id: apply
        run: terraform apply -auto-approve -var 'pr_number=${{ github.event.number }}' -var 'commit_hash=${{ github.sha }}' -var 'region=${{ secrets.AWS_REGION }}'
        working-directory: infra
        continue-on-error: true

      - name: Login to Amazon ECR
        if: ${{ steps.apply.outcome == 'failure' }}
        uses: aws-actions/amazon-ecr-login@v1

      - name: Push Container(Only synchronize pull request)
        if: ${{ steps.apply.outcome == 'failure' }}
        run: |
          docker build -t ${{ secrets.AWS_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com/pullrequest-${{ github.event.number }}:latest .
          docker push ${{ secrets.AWS_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com/pullrequest-${{ github.event.number }}:latest

初回のみterraform applyが成功し、二回目以降はすでに同じ名前のリソースが生成されているので失敗するようになっています。
またPRの情報(PRやIssueの番号)などを使い、PRごとに環境を作れるようにしています。

二回目以降(つまり追加でPRにコミットがpushされた場合は以下のように失敗した結果をもとにECRへ新しいコンテナをビルドしてプッシュするようにしています。

      - name: Apply
        id: apply
        run: terraform apply -auto-approve -var 'pr_number=${{ github.event.number }}' -var 'commit_hash=${{ github.sha }}' -var 'region=${{ secrets.AWS_REGION }}'
        working-directory: infra
        continue-on-error: true

      - name: Login to Amazon ECR
        if: ${{ steps.apply.outcome == 'failure' }}
        uses: aws-actions/amazon-ecr-login@v1

      - name: Push Container(Only synchronize pull request)
        if: ${{ steps.apply.outcome == 'failure' }}
        run: |
          docker build -t ${{ secrets.AWS_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com/pullrequest-${{ github.event.number }}:latest .
          docker push ${{ secrets.AWS_ID }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com/pullrequest-${{ github.event.number }}:latest

正直、この辺はもう少しやりようがあるとは思いますね……。
とりあえず、動くものを作りたかったので一旦はこれでOKとしてます(何かいい知見ご存じの方いればご教授いただければ幸いです)

またPRがマージされた(またはクローズされた)場合は以下のように作成されたリソースをAWS CLIで削除するようにしています。

name: 'Delete staging with pull request'

on:
  pull_request:
    types: [closed]

jobs:
  terraform:
    name: 'Terraform'
    runs-on: ubuntu-latest

    defaults:
      run:
        shell: bash

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Configure aws credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Get AppRunner Service ARN
        id: apprunner-service-arn
        run: |
          service_arn=$(aws apprunner list-services --query "ServiceSummaryList[?ServiceName=='pullrequest-${{ github.event.number }}'].ServiceArn | [0]")
          echo "::set-output name=stdout::$service_arn"
      - name: Delete AppRunner Service
        run: aws apprunner delete-service --service-arn ${{ steps.apprunner-service-arn.outputs.stdout }}

      - name: Delete ECR repository
        run: aws ecr delete-repository --repository-name pullrequest-${{ github.event.number }} --force

      - name: Get Role attachment policy
        id: role-attachment-policy
        run: |
          role_attachment_policy=$(aws iam list-attached-role-policies --role-name pullrequest-4-service-role --query "AttachedPolicies[0].PolicyArn")
          echo "::set-output name=stdout::$role_attachment_policy"
      - name: Dettach policy
        run: aws iam detach-role-policy --role-name pullrequest-${{ github.event.number }}-service-role --policy-arn ${{ steps.role-attachment-policy.outputs.stdout }}

      - name: Delete role
        run: aws iam delete-role --role-name pullrequest-${{ github.event.number }}-service-role

これのおかげでテスト用に作成された環境を削除し忘れることが回避できています。
この辺ももう少しきれいにしたい感じはありますね……。

今後

今回検証用としてPR単位でのテスト環境自動構築をやってみましたが、大分いい感じではありますね。
なので、一旦仕事のほうでつかえないか導入してみて検証を進めていきたいと思います。

今後課題になりそうなのは実用的なWebアプリケーションなどではDBとの接続(RDSやVPCの設定)が必要になりそうなので、そのあたりをどうするかですね。
また、PRにコミットが積まれるたびにtarraform applyされているのは非常に微妙なのでそのあたりもどうにかしたいですね。

さらに、フロントエンドとバックエンドが分かれているような場合ではAPI側をどう呼び出すのかなどが課題になりそうです。

RailsをAppRuner/RDS/ECRな環境にデプロイできるようにしてみた

Railsで作成されたアプリケーションを、AWS上のAppRunner/RDS/ECRを使った環境にデプロイできるようにしてみた時のメモです。

ついでに、Terraformを使ってインフラ周りもコードで管理できるようにしてみた感じです。

 

作ったもの

github.com

 

ほとんど素のRailsアプリをAppRunnerにデプロイできるようにしてみたものです。

現状ではGitHubActionsを使ったECRへのPushなどはできてませんが、そのうち対応したい……。

 

基本的に頑張ったところはTerraform周りで、以下のようにRDS上にDBが作成されたタイミングでDBへのマイグレーションを走らせたり

github.com

 

ECRの環境が作られたタイミングでコンテナをビルドしてpushしたり

github.com

 

その辺の最初にインフラ周りを構築する際の設定を頑張った感じですね。

 

経緯や背景など

  • 住んでる街(浜田市)向けのサービスとかを作る際にできるだけ使い慣れたRailsを使って開発したかった。
  • インフラとかを細かくメンテナンスしたくなかったので、AWS使って楽したい
  • AppRunnerが最近、VPCに一部対応した
  • AppRunnerでのコンテナ運用が依然試して楽だったので使いたい

などのモチベーションがあってこの構成にした感じですね。

実際にやってみて勉強になった感じ(主にTerraform周り)

 

今後

今回作ったものは実際に運用していく感じではないですが、これをもとにほかの言語(例えばコンテナとの相性がいいGoとか、シングルバイナリが作れるRustとか)でサービスを開発して運用していくのは良さそう。

 

あと前からチマチマ作ってる自分が使うようのWebフレームワークとかと合わせてみるのも面白そう

github.com

 

この辺はRubyでのシングルバイナリ生成とか詳細調べて対応したいかな……?

 

Goでicalendarを生成してみた

はじめに

Goでicalendarを生成してみたいけどどうやるんだっけ?って人向けの記事です(多分そんなにいないと思いますが……)

背景

仕事のコードで予約されているデータなどをGoogleカレンダーなどへ連携されるようにしたいという話が出たのが事のきっかけです。
で、同僚の人と「どうしましょうかー」と話してて、「icalendarを使えばよさそう」となり、実際に実装してみた感じです。

作ったもの

github.com

凄くシンプルに実装したサンプルになります。

使っているライブラリとしては以下のものを使っています。

  • gin-gonic/gin(APIサーバー用)

github.com

github.com

やったこと

基本的にシンプルなginのサーバーを書いて、

func main() {
    err := godotenv.Load(".env")
    if err != nil {
        fmt.Printf("can not load .env!")
    }

    r := gin.Default()
    r.GET("/icals", func(c *gin.Context) {
        ical := generateIcal()
        c.String(http.StatusOK, ical)
    })
    r.Run()
}

あとはただgolang-ical使って構造体経由でカレンダーデータを作成した感じですね。

type Calendar struct {
    Title string
    StartAt time.Time
    EndAt time.Time
    ZoomURL string
}

func generateIcal() string {
    cal := ical.NewCalendar()
    cal.SetMethod(ical.MethodRequest)

    var calendars []Calendar

    for i := 0; i < 10; i++ {
        calendar := Calendar{
            Title: fmt.Sprintf("HALO %d", i),
            StartAt: time.Now().Add(time.Duration(i) * time.Hour),
            EndAt: time.Now().Add(time.Duration(i + 1) * time.Hour),
            ZoomURL: os.Getenv("ZOOM_URL"),
        }

        calendars = append(calendars, calendar)
    }

    for _, calendar := range calendars {
        event := cal.AddEvent(calendar.Title)
        event.SetStartAt(calendar.StartAt)
        event.SetEndAt(calendar.EndAt)
        event.SetSummary(calendar.Title)
        event.SetDescription(calendar.Title)
        event.SetDescription(calendar.ZoomURL)
        event.SetURL(calendar.ZoomURL)
        event.SetLocation(calendar.ZoomURL)
    }

    return cal.Serialize()
}

実用性とか考えるとZoomとかのURLも添付できたら面白そうだったのでZoomのURLとかも追加してる感じですね。 意外と癖なくサクッと作れたので簡単なカレンダーAPIとかGoで書くのも面白そうです。

あとは、ngrokを使って、Googleカレンダーとかに追加できるようにして動作確認したりくらいですね。

ngrok http 8080

今後

実際に仕事で使うコードにするとなると色々考えないといけないことも多いですが、すごく簡単にicalendarsを生成できたのでいい感じです。

GoでGoの雛型コードを自動生成できるようにしてみた

はじめに

仕事ではもっぱらGoを書いてて、同じようなコードを結構毎回書いたりしてるのがストレスになってる人向けの記事です。

GoでGoの雛型コードを自動生成できるライブラリ dave/jennifer を使ってコマンド経由で楽に生成できるようにしてみました。

github.com

作ったもの

github.com

使い方としては以下のようにmake経由で作成したいコードのtypeとnameを指定すれば自動的に雛型が生成されます。

make code-gen type=model name=UserProfile

ちなみに↑のコマンドで生成されるのは以下のようなモデルです。

package model

type UserProfile struct{}

作った背景

仕事でGoを使っているんですが、どうしても同じようなコードを毎回手で書く辛さを感じてました。 またRailsとかLaravelではコマンド経由で大まかなコードを自動生成できますが、仕事では特にそういった自動生成できる環境ではなかったので愚直にコードを書いており、微妙な印象もありました。

それに手書きで書いてるとちょっとしたスペルミスとかもあったりしてビルドが通らず、開発体験が良くないなとも感じてました。

そこで、何かコードを自動生成できるライブラリとかないかなと探していたところ dave/jennifer を見つけたので試しに作ってみた感じです。

今後

とりあえず簡単にコードの雛型は生成できるようになったので、仕事でもつかえるようにパスや諸々の修正とかしてみようかと思います。