年の瀬に何やってんだという感じではありますが、ちょっとしたタスク整理でALB一式をTerraformに落としたくなる場面があったので作業メモを残します。*1 試行錯誤した結果をそのままメモとして残していきますので、上級者が良いやり方をまとめた記事ではないことにご注意ください。
- importするリソース
- 前提
- 作業開始
- まとめ
importするリソース
Importしてコード管理したいのは、以下のリソースです
- ALB
- TargetGroup
- Cognito --> 残念ながらCognitoのimportは対応してませんでした、現状は手書きしてimportしかなさそうです *2
前提
該当AWSのプロファイルは設定済みです。環境変数にもセットされています。
作業開始
それではやっていきます。
Terraforming準備
まずはTerraformingを準備します。Google社が作ってるTerraformerでも良いのですが、老舗な方を使ってみようとしてます。
gemでサクッと入るらしいですが、既存環境を汚してもあれなので、Dockerでやるとします。
FROM ruby:2.6-slim RUN gem install terraforming ENTRYPOINT ["terraforming"]
早速ビルド
$ docker build -t localhost/terraforming Sending build context to Docker daemon 58.88kB Step 1/3 : FROM ruby:2.6-slim 2.6-slim: Pulling from library/ruby 8ec398bc0356: Pull complete 05b696148f80: Pull complete adf092395f95: Pull complete 6a36680cb06f: Pull complete d18e1cb85888: Pull complete Digest: sha256:266f8f86a1de812612505aa5d5e7adf5c3ff8b06fb997b95cefa18fd8249fcbe Status: Downloaded newer image for ruby:2.6-slim ---> 49abb10f297c Step 2/3 : RUN gem install terraforming ---> Running in 15abb1da5d20 Successfully installed jmespath-1.4.0 Successfully installed aws-partitions-1.260.0 Successfully installed aws-eventstream-1.0.3 Successfully installed aws-sigv4-1.1.0 Successfully installed aws-sdk-core-3.86.0 Successfully installed aws-sdk-autoscaling-1.30.0 Successfully installed aws-sdk-cloudwatch-1.31.0 Successfully installed aws-sdk-dynamodb-1.41.0 Successfully installed aws-sdk-ec2-1.129.0 Successfully installed aws-sdk-efs-1.23.0 Successfully installed aws-sdk-elasticache-1.29.0 Successfully installed aws-sdk-elasticloadbalancing-1.19.0 Successfully installed aws-sdk-elasticloadbalancingv2-1.39.0 Successfully installed aws-sdk-iam-1.32.0 Successfully installed aws-sdk-kms-1.27.0 Successfully installed aws-sdk-rds-1.74.0 Successfully installed aws-sdk-redshift-1.35.0 Successfully installed aws-sdk-route53-1.30.0 Successfully installed aws-sdk-s3-1.60.1 Successfully installed aws-sdk-sns-1.21.0 Successfully installed aws-sdk-sqs-1.23.1 Successfully installed multi_json-1.12.2 Successfully installed thor-1.0.1 Successfully installed terraforming-0.18.0 24 gems installed Removing intermediate container 15abb1da5d20 ---> 3a82f375b08d Step 3/3 : ENTRYPOINT ["terraforming"] ---> Running in 061f188dbe75 Removing intermediate container 061f188dbe75 ---> 6c32df018ba0 Successfully built 6c32df018ba0 Successfully tagged localhost/terraforming:latest
うまくいきました。オプションなし実行で、ヘルプが表示されるのを確認しました。
docker run localhost/terraforming Commands: terraforming alb # ALB terraforming asg # AutoScaling Group terraforming cwa # CloudWatch Alarm terraforming dbpg # Database Parameter Group terraforming dbsg # Database Security Group terraforming dbsn # Database Subnet Group terraforming ddb # DynamoDB terraforming ec2 # EC2 terraforming ecc # ElastiCache Cluster terraforming ecsn # ElastiCache Subnet Group terraforming efs # EFS File System terraforming eip # EIP terraforming elb # ELB terraforming help [COMMAND] # Describe available commands or one specific ... terraforming iamg # IAM Group terraforming iamgm # IAM Group Membership terraforming iamgp # IAM Group Policy terraforming iamip # IAM Instance Profile terraforming iamp # IAM Policy terraforming iampa # IAM Policy Attachment terraforming iamr # IAM Role terraforming iamrp # IAM Role Policy terraforming iamu # IAM User terraforming iamup # IAM User Policy terraforming igw # Internet Gateway terraforming kmsa # KMS Key Alias terraforming kmsk # KMS Key terraforming lc # Launch Configuration terraforming nacl # Network ACL terraforming nat # NAT Gateway terraforming nif # Network Interface terraforming r53r # Route53 Record terraforming r53z # Route53 Hosted Zone terraforming rds # RDS terraforming rs # Redshift terraforming rt # Route Table terraforming rta # Route Table Association terraforming s3 # S3 terraforming sg # Security Group terraforming sn # Subnet terraforming snss # SNS Subscription terraforming snst # SNS Topic terraforming sqs # SQS terraforming vgw # VPN Gateway terraforming vpc # VPC Options: [--merge=MERGE] # tfstate file to merge [--overwrite], [--no-overwrite] # Overwrite existing tfstate [--tfstate], [--no-tfstate] # Generate tfstate [--profile=PROFILE] # AWS credentials profile [--region=REGION] # AWS region [--assume=ASSUME] # Role ARN to assume [--use-bundled-cert], [--no-use-bundled-cert] # Use the bundled CA certificate from AWS SDK
Terraformingでimportしようとしたが...
ALB
サクッと以下のコマンドを叩きます。
docker run -e AWS_REGION -e AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY localhost/terraforming alb > alb.tf
作成されたalb.tfを眺めます。SGやサブネットがIDベタ書きですが、これは仕方ないでしょう、あとでいい感じに直そうと思います。
resource "aws_alb" "aws-analytics" { idle_timeout = 60 internal = false name = "aws-analytics" security_groups = ["sg-hogehoge"] subnets = ["subnet-fugafuga", "subnet-mogemoge"] enable_deletion_protection = true access_logs { bucket = "hoge-alb-accesslog" enabled = true prefix = "aws-analytics" } tags { "analytics" = "true" } } ...
TargetGroup....はTerraformingにはないっぽい
どうやらterraformingはTargetGroupのインポートに対応していない様です。自分で書いて terraform import をしても良いのですが、もう一つのTerraform ImportツールであるTerraformerを見たところ、対応している様なのでそちらに切り替えたいと思います。
仕切り直しでTerraformerを準備
terraformerはGoogleCloudPlatformのオーガニゼーション配下に作られていますが、GCPだけではなく、AWSやAzureと言ったメジャークラウドには対応していました、さすがです。
AWSに関していうと、ALBはもちろん、TargetGroupやListenerRuleにも対応しており、ALBに限ればTerrafomingより対応リソースが多いです。
インストールは簡単で、Go言語で書かれているだけあってバイナリを一個持ってくるだけでした。よって直接Macに入れてしまいます。
export PROVIDER={all,google,aws,kubernetes} curl -LO https://github.com/GoogleCloudPlatform/terraformer/releases/download/$(curl -s https://api.github.com/repos/GoogleCloudPlatform/terraformer/releases/latest | grep tag_name | cut -d '"' -f 4)/terraformer-${PROVIDER}-darwin-amd64 chmod +x terraformer-${PROVIDER}-darwin-amd64 sudo mv terraformer-${PROVIDER}-darwin-amd64 /usr/local/bin/terraformer
コマンドを実行して問題なさそうなことを確認します。ついでにバージョンコマンドも。
$ terraformer Usage: [command] Available Commands: help Help about any command import Import current state to Terraform configuration plan Plan to import current state to Terraform configuration version Print the version number of Terraformer Flags: -h, --help help for this command --version version for this command Use " [command] --help" for more information about a command. $ terraformer version Terraformer v0.8.5
とここまでやって、brewで入ることがわかりました(そりゃそうか)。 手動で入れてしまったものは消して、brewで入れ直すことにします。
rm /usr/local/bin/terraformer brew install terraformer
TerraformerでALBをimport
terrafomerのインストが終わったので、早速albをimportしていきます。 サンプルコマンドを参考に、albをオプションに追加して実行。
$ terraformer import aws --resources=vpc,subnet,alb 2019/12/31 13:18:35 aws importing default region 2019/12/31 13:18:35 aws importing... vpc 2019/12/31 13:18:36 plugin error 1: open /Users/morihaya/.terraform.d/plugins/darwin_amd64: no such file or directory 2019/12/31 13:18:36 open /Users/morihaya/.terraform.d/plugins/darwin_amd64: no such file or directory
怒られました。どうやら何か設定が必要みたいですので、ドキュメントを読み直します。
どうもpluginがないことが問題に見えるため、ソースインストールに手順のあった、 init.tf
を配置して terraform init
をやってみます。
$ vi init.tf --- provider "aws" {} --- $ terraform init Initializing the backend... Initializing provider plugins... - Checking for available provider plugins... - Downloading plugin for provider "aws" (hashicorp/aws) 2.43.0... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 2.43" Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
気を取り直してterraformerを再実行
$ terraformer import aws --resources=vpc,subnet,alb 2019/12/31 13:26:18 aws importing default region 2019/12/31 13:26:18 aws importing... vpc 2019/12/31 13:26:28 Refreshing state... aws_vpc.tfer--vpc-hogehoge ... 2019/12/31 13:26:30 aws importing... subnet 2019/12/31 13:26:38 Refreshing state... aws_subnet.tfer--subnet-hogehoge ... 2019/12/31 13:28:46 aws Connecting.... 2019/12/31 13:28:48 aws save vpc 2019/12/31 13:28:48 aws save tfstate for vpc 2019/12/31 13:28:48 aws save subnet 2019/12/31 13:28:48 aws save tfstate for subnet 2019/12/31 13:28:48 aws save alb 2019/12/31 13:28:48 aws save tfstate for alb
動きました。既存リソースが全部取られたので、ログは大量すぎて省略しています。
コマンドが動いた結果、 generated
というディレクトリが生成されていました。
treeコマンドで見ると以下の様なファイル群ができています。いい感じですね。
$ tree generated/ generated/ └── aws ├── alb │ ├── lb.tf │ ├── lb_listener.tf │ ├── lb_listener_rule.tf │ ├── lb_target_group.tf │ ├── lb_target_group_attachment.tf │ ├── outputs.tf │ ├── provider.tf │ ├── terraform.tfstate │ └── variables.tf ├── subnet │ ├── outputs.tf │ ├── provider.tf │ ├── subnet.tf │ ├── terraform.tfstate │ └── variables.tf └── vpc ├── outputs.tf ├── provider.tf ├── terraform.tfstate └── vpc.tf 4 directories, 18 files
TerraformerでRoute53を追加でimport
ここでハッと気付きましたが、r53を取得し忘れました。追加で行けるのかわかりませんが、とりあえずやってみます。vpcやsubnetは取得済みなので、単純にroute53だけ指定します。
$ terraformer import aws --resources=route53 2019/12/31 13:34:09 Refreshing state... aws_route53_record.tfer--hogehoge-_NS_ 2019/12/31 13:34:09 Refreshing state... aws_route53_zone.tfer--hogehoge-co 2019/12/31 13:34:09 Refreshing state... aws_route53_record.tfer--hogehoge_SOA_ ... 2019/12/31 13:35:14 aws Connecting.... 2019/12/31 13:35:14 aws save route53 2019/12/31 13:35:14 aws save tfstate for route53
問題なく動作しました。treeを再びgeneratedディレクトリに実行すると、route53ディレクトリが生成されていました。素晴らしい。
$ tree generated/ generated/ └── aws ├── alb │ ├── lb.tf │ ├── lb_listener.tf │ ├── lb_listener_rule.tf │ ├── lb_target_group.tf │ ├── lb_target_group_attachment.tf │ ├── outputs.tf │ ├── provider.tf │ ├── terraform.tfstate │ └── variables.tf ├── route53 │ ├── outputs.tf │ ├── provider.tf │ ├── route53_record.tf │ ├── route53_zone.tf │ └── terraform.tfstate ├── subnet │ ├── outputs.tf │ ├── provider.tf │ ├── subnet.tf │ ├── terraform.tfstate │ └── variables.tf └── vpc ├── outputs.tf ├── provider.tf ├── terraform.tfstate └── vpc.tf 5 directories, 23 files
Terrafomerが生成したファイルを確認して、利用したいものだけ拾っていく
ここからが大変な作業です。generatedに作成されるのは、利用したAWS権限が参照可能な全てのリソースになっているので、必要なものをピックアップします。ロードバランサにつけた名前を検索して、それ以外のところを削除していきました。
lb.tf
lb.tfはALBの一覧になっているので、必要なALB以外をサクッと削除しました。簡単でした。
lb_listenere.tf
lb_listenere.tfはリスナーの一覧です。80と443の2つしかありませんので、LB名でフィルタできたのでそこまで大変ではありませんでした。
lb_listener_rule.tf
lb_listener_rule.tfはリスナールールの一覧で、大量に出ていましたが、LB名でフィルタすれば必要部分を抜粋することができました。
lb_target_group.tf
lb_target_group.tfはTagetGroupの一覧で、LB名とは独立しているため、TargetGroupのnameの値を見ながら人間が判断するしかなさそうでした。AWSコンソールでL B順にソートした後、一つ一つTargetGroup名を確認して検索してピックアップしました。
lb_target_group_attachment.tf
lb_target_group_attachment.tfはTargetGroupとEC2インスタンスとの紐付けに使用します。これもTargetGroupのarnから抜粋していきます。
リファクタリング
だいたいの整理が終わったら、albディレクトリで terraform plan
を実行してみます。恐ろしい数のDestroy数が出ますので、危険な状態です。
今のterraform.tfstateは削除し、リファクタしながらimportしていくのが良さそうです。またoutputs.tfは必要なさそうなので消します。*3
$ rm terraform.tfstate outputs.tf
terraformerはvariables.tfにalbのstateも参照する様になっているため、そちらもコメントアウトしてしまいます。
# data "terraform_remote_state" "alb" { # backend = "local" # config = { # path = "../../../generated/aws/alb/terraform.tfstate" # } # } data "terraform_remote_state" "subnet" { backend = "local" config = { path = "../../../generated/aws/subnet/terraform.tfstate" } }
その後は data.terraform_remote_state.alb.
で検索しながらリファクタをしていきます。対象としては以下の2種類のみの参照でしたので、直すのは難しくありませんでした。
- lb_listener.tfのload_balancer_arn
- lb_listener_rule.tfのlistner_arn
具体的には以下の様に直します。
load_balancer_arn = "${data.terraform_remote_state.alb.outputs.aws_lb_tfer-hoge_id}" を下の様に load_balancer_arn = aws_lb.tfer--hoge.arn listener_arn = "${data.terraform_remote_state.alb.outputs.aws_lb_listener_tfer--arn-003A-aws-003A-elasticloadbalancing-003A-ap-002D-northeast-002D-1-003A-hoge-003A-listener-002F-app-002F-hogehoge_id}" を下の様に listener_arn = aws_lb_listener.tfer--arn-003A-aws-003A-elasticloadbalancing-003A-ap-002D-northeast-002D-1-003A-hoge-003A-listener-002F-app-002F-shoge-002F-3d665b2c8a52d5a3-002F-hogehoge.arn
terraform planが通る様になったことを確認し、長すぎるIDをわかりやすくて短いものに変更します。
手動でterraform import
リファクタが終われば、後は順にterraform importをしていきます。
大きいものから順にやる必要があるため以下の順番でやります。
- ALB
- Listener
- Lstener Rule
- TargetGroup
- TargetGroupAttachment
というわけでまずはALBを。この手の作業ではARNが必要になりますが、AWSのWebコンソールは優れているので大抵はコピーが簡単にできます。
$ terraform import aws_lb.hogefuga arn:aws:elasticloadbalancing:ap-northeast-1:moge:loadbalancer/app/hogefuga/3d665b2c8a52d5a3 aws_lb.hogefuga: Importing from ID "arn:aws:elasticloadbalancing:ap-northeast-1:moge:loadbalancer/app/hogefuga/3d665b2c8a52d5a3"... aws_lb.hogefuga: Import prepared! Prepared aws_lb for import aws_lb.hogefuga: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-1:moge:loadbalancer/app/hogefuga/3d665b2c8a52d5a3] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
続いてListner。
# httpの方 $ terraform import aws_lb_listener.hogefuga-http arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener/app/hogefuga/3d665b2c8a52d5a3/19104a63ac78c527 aws_lb_listener.hogefuga-http: Importing from ID "arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener/app/hogefuga/3d665b2c8a52d5a3/19104a63ac78c527"... aws_lb_listener.hogefuga-http: Import prepared! Prepared aws_lb_listener for import aws_lb_listener.hogefuga-http: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener/app/hogefuga/3d665b2c8a52d5a3/19104a63ac78c527] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform. # httpsの方 $ terraform import aws_lb_listener.hogefuga-https arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener/app/hogefuga/3d665b2c8a52d5a3/85de3679a3597e22 aws_lb_listener.hogefuga-https: Importing from ID "arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener/app/hogefuga/3d665b2c8a52d5a3/85de3679a3597e22"... aws_lb_listener.hogefuga-https: Import prepared! Prepared aws_lb_listener for import aws_lb_listener.hogefuga-https: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener/app/hogefuga/3d665b2c8a52d5a3/85de3679a3597e22] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
続いて Listener Rule、この辺りから数が多くなって面倒になってきますが、仕方ない。。。
terraform import aws_lb_listener_rule.aws-design-hoge01 arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener-rule/app/hogefuga/3d665b2c8a52d5a3/85de3679a3597e22/000ece86c9d51211 aws_lb_listener_rule.aws-design-hoge01: Importing from ID "arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener-rule/app/hogefuga/3d665b2c8a52d5a3/85de3679a3597e22/000ece86c9d51211"... aws_lb_listener_rule.aws-design-hoge01: Import prepared! Prepared aws_lb_listener_rule for import aws_lb_listener_rule.aws-design-hoge01: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-1:moge:listener-rule/app/hogefuga/3d665b2c8a52d5a3/85de3679a3597e22/000ece86c9d51211] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform. #以降は同じ感じで繰り返す
続いてTargetGroupです、かなり単純な作業になってきて、辛い感じになりますが、考え方を変える必要があります。これは本来コードで書くべきだったはずの作業を、手でやってしまった"ツケ"を払っているのです。存在するべきコードを今作っていると考えれば、少しは気が紛れるのではないでしょうか(そうでもないかも)
軽快な音楽など聞きながらやることをお勧めします。
terraform import aws_lb_target_group.aws-design-hoge01 arn:aws:elasticloadbalancing:ap-northeast-1:moge:targetgroup/aws-design-hoge01/piyopiyo aws_lb_target_group.aws-design-hoge01: Importing from ID "arn:aws:elasticloadbalancing:ap-northeast-1:moge:targetgroup/aws-design-hoge01/piyopiyo"... aws_lb_target_group.aws-design-hoge01: Import prepared! Prepared aws_lb_target_group for import aws_lb_target_group.aws-design-hoge01: Refreshing state... [id=arn:aws:elasticloadbalancing:ap-northeast-1:moge:targetgroup/aws-design-hoge01/piyopiyo] Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform. #以降は同じ感じで繰り返す
target_group_attachmentはimportできないので諦める
よーしもう少しだ、次は target_group_attachment と思ったのですが、残念なことに terraform import
に対応していませんでした。 逆にいうと対応してしまっているterraformerすごいな、、という感想になります。
ここで選択肢は二つです。
- target_group_attachment は既存については諦める(コメントアウトしてimportできる将来に期待しつつ、新規分からコードでちゃんとやる
- terraformerのstateファイルをやっぱり使う(いらない部分はterraform state rmなどで外す)
今回はあっさりと既存分については諦めることにしました。
VPC周りをdataで用意
さらにリファクタリングを進めます。次はVPC周りをdataファイルとして用意します。 理由として、今回terraform管理下におきたいのは特定のALB一式のみですので、それ以外のリソースは管理できる様にしたくはありません。そのため必須となるVPC関連とR53のZoneなどはdataで用意します。
data.tfは以下の雰囲気になりました。
# VPC関連 data "aws_vpc" "oisix_vpc" { id = "vpc-hoge" } data "aws_subnet" "infra-kanri-az1a" { id = "subnet-fuga" } data "aws_subnet" "infra-kanri-az1c" { id = "subnet-moge" }
ここまでくるとterrafomerが作成したvariables.tfが不要になるので削除します。
SecurityGroupも追加
SecurityGroupは当初importしようとしましたが、security_group_ruleに分解?する事象が発生したので同じルールを新規で作り、ALBにアタッチして入れ替える感じにしました。
cognitoのimport
ALBで認証を行うためのcognitoについては、terraformerは対応していないので手動でファイルを作りました。
user_poolは既存のもので良く、user_pool_clientのcallback_urlsを管理するのが目的です。
仕上げ
backend.tfを作ってs3にstatefileをおく様にします。 そしてディレクトリをgitリポジトリにアップしておけば、一旦完了です。
terraform { backend "s3" { bucket = "hoge-common-terraform-statefiles" key = "infra-alb-hogeterraform.tfstate" region = "ap-northeast-1" } }
ここまでやってディレクトリ構成は以下となりました。
$ tree . ├── README.md ├── backend.tf ├── cognito.tf ├── data.tf ├── generated ├── lb.tf ├── lb_listener.tf ├── lb_listener_rule.tf ├── lb_target_group.tf ├── lb_target_group_attachment.tf ├── provider.tf └── security_group.tf 1 directory, 11 files
最後に各リソースを、意味のある形でファイル分割をしなおします。1サービス(URL) = 1ファイルの形です。
最終的に以下のようなファイル構成になりました。
. ├── README.md ├── backend.tf ├── cognito.tf ├── data.tf ├── generated ├── lb.tf ├── lb_listener.tf ├── provider.tf ├── resource_1_xxx-redmine01.tf ├── resource_2_xxx-sre-gitlab01.tf ├── resource_3_xxx-design-gitlab01.tf ├── resource_4_xxx-gitlab.tf ├── resource_5_awx-morihaya-com.tf ├── resource_6_zabbix-morihaya-com.tf ├── resource_7_xxx-dev-jenkins01.tf ├── resource_8_xxx-unyou-jenkins01.tf ├── resource_9_infra-jenkins01.tf └── security_group.tf
ポイントとしてはresource_ で始まるファイル名の数字が、aws_lb_listener_ruleのpriorityで指定する値になっています。
resource "aws_lb_listener_rule" "xxx-gitlab" { action { ... listener_arn = aws_lb_listener.hogehoge-https.arn priority = "2" }
ここまでくると、新しいサービス(URL)を追加する場合に、既存のresource_ファイルをコピーして少量の変更だけで、簡単に設定を行っていくことができるはずです。
今後やること
github actionsでのCICD実装などするとさらに良いでしょう。prでplanしてmergeでapplyするやつです。
まとめ
とりあえずは当初の目的を果たせたので本作業はOKとしました。
所感としては、今回はterraformerの作ったHCLを少なからずリファクタリングしましたが、毎回これをやるのは辛いので、ツールが出したものはそのまま使う思想や工夫が必要なのかもな、と考えたりしました。