goa (v1): `goagen --regen` と `goagen --force` の挙動 #goadesign

[goa](https://github.com/goadesign/goa)を使ったサービス開発では、まずAPIやresourceの定義をdesignと呼ばれるコードに記述し　→ それをinputとしてgeneratorで実稼働コードの雛形を生成　するという開発手順を踏む事になるが、新規でdesignを書くだけではなく既存designの修正時にも同様に再生成作業が発生する事がある。goaが提供するコードジェネレータ `goagen` には `--regen` という再生成の為に用意されたと思われるオプションが提供されているが、どういう挙動をするか調査したのでメモ

## 前提条件
* goa ver 1.3.0
* 対象controller actionはGET（参照系処理）
* controllerのコードに既に非・自動生成なコード（主にビジネスロジック）も混ざっているケースで、controller のdesignに変更が発生 => その変更差分をgoagenを再実行してcontrollerコードに摘要したい。というケース

## goaで提供されている `goagen --regen` と `goagen --force`
`goagen` 再生成を意識して用意されたと思われるオプションは `--regen` と `--force` の2つある。例えば `goagen main ...` コマンドでcontrollerを生成する際にこの2つのオプションがどういう挙動をするかは [goagen/gen_main/generator.goの GenerateControllerメソッド](https://github.com/goadesign/goa/blob/master/goagen/gen_main/generator.go#L121) のコードを読むと分かる

```go:抜粋
if regen {
  actionImpls, extractedImports, err = extractControllerBody(filename)
  if err != nil {
    return "", err
  }
  os.Remove(filename)
}
if force {
  os.Remove(filename)
}
```


* `--force` の場合はファイルそのものが自動生成ファイルで上書きされる。なので独自処理コードを追加していた場合はそのコードはなくなる
* `--regen` の場合は、goagen直後のコードに含まれる `start_implement` というコメントと `end_implement` というコメントの存在を探し、それらの間に独自追加されたコードを維持しつつ、それ以外の部分が上書き される
  * つまり独自処理は、この両コメントを残しつつ、両コメントの間に書くと良さそう
　

`--regen` の際、独自追加コード or NOT を判定する為の解析処理が [https://github.com/goadesign/goa/blob/master/goagen/gen_main/generator.go#L74](https://github.com/goadesign/goa/blob/master/goagen/gen_main/generator.go#L74)で行われている。


* 現存しているcontrollerコードの `// XXXController_ACTIONNAME: start_implement` というコメントと、 `// XXXController_ACTIONNAME: end_implement` というコメントで挟まれているコードブロックを探す
* このブロック（の各行）を `actionImpls[match[1]] = strings.Join(block, "\n")` という変数に退避。最終的にこの `actionImpls` をreturnする
* このブロック以外（start ... end の外）は、genされたコードで上書きする

という挙動。

この際に `end_implement` コメントの直後に `res := &app.XXXList{}` 的な空struct代入コードも復活するのだけど、例えば `end_implement` コメントより前の独自処理記載部分に `res := 処理結果` という代入を行うコードがある場合だと、この空struct代入コードにより結果が `res` 変数が上書きされる事になる。

```go:こうなる
  // HogeController_SearchHoge: start_implement

  // Put your logic here
  res := 実際の処理結果  // 再生成でも維持

  // HogeController_SearchHoge: end_implement
  res := &app.HogeList{}  // ★再生成で空struct上書きコード復活
  return ctx.OK(res)
```

これを回避する為、最初「実際の処理結果は `res` という変数以外の変数を使うようにする」という策を思い付いたのだが、controllerの自動生成では例えばGETの正常系なら `return ctx.OK(res)` という結果返却コードを生成してくれるので、このreturnで使っている変数も `res` 以外にrenameする　という修正が発生する事になる。つまり自動生成部分に手を加える　という事になり、保守性の観点で懸念があるものの、 "--regen way" に乗るなら再生成はこの流れで行う事になりそう。

「空struct代入コードは `end_implement` より前の行に生成されるようなpull reqを出す」という案も考えたのだけど、空struct代入を `end_implement` の後ろにしている意図を完全に理解し切れていなかった為、一旦却下

## 補足: gormaでmodelを管理している場合
[gorma](https://goa.design/ja/extend/gorma/)はgoaのプラグインとして公開されているgormベースのO/Rマッパーで、このプラグインを導入する事で「modelを独自DSLでdesignとして定義」する事ができるようになり、このdesignをinputとして `goagen gen` コマンドを実行する事で、gormベースのmodelのコードが自動生成される。デフォルトでは、

* `モデル名.go` というコードを生成: 基本的なCRUD処理はココに自動定義される
* `モデル名_helper.go` というコードを生成: "controllerで使用可能なレスポンス用型（media_type）への変換を含んだ参照系" 処理はココに自動定義される

という挙動になっており、独自コードは単にファイルを分けて定義するようにすれば、再生成・上書き　の考慮は不要になる。例えばgoa公式のサンプルでは独自処理は `モデル名_addon.go` というファイルに分けている。ただこの場合も、例えば「modelの項目構成が変わった」り、「media_typeの内部定義が変わった」りした場合に、その変更を考慮した修正が独自処理にも発生する事はある。