おでーぶでおでーぶ

いろいろ書く。いろいろ。

Kotlin DSL を考慮した Gradle Plugin を記述するために必要だったこと

とある Gradle Plugin を 2.0.0 に移行する際、v1 から Kotlin DSL を使っていた人の環境でちょっと問題が発生したというツイートを見たので、Kotlin DSL がどうやって DSL Marker なしに lambda で書けるようにしてるのかちょっと調べてみた。ここで記述している問題は 2.0.1 では修正されていて、また Kotlin DSL での移行ステップも README に追記しておきました。

github.com

TL;DR

  • 外に見せる境界で def を使うのは避けておいた方が無難
  • Kotlin DSL は拡張関数で delegate してて、見るべきメソッドが違うかもしれないから気をつけよう
  • Kotlin と Gradle の言語仕様の違いに気をつけよう
  • kotlin-dsl を apply して開発しないと Groovy と Kotlin DSL で同じような Closure (Lambda) の記法に出来ない(多分) (2/25 追記: DomainObjectでない場合)

lambda と Closure の型変換

v1 では動いていた以下の記述が 2.0.0 だと動かず、 2.0.0 から導入された deployments であれば動くという問題が発生していた。

deploygate {
  apks { ... }
}

これは下記の通りに書き換えると apks 記述でも動く。

deploygate {
  apks(closureOf<NamedDomainObjectContainer<NamedDeployment>> { ... }
}

def apks(Closure) を呼び出そうとするが、渡している lambda と Closure の間で型変換が不可能であるので発生していた。これはclosureOf を使い、型情報も明示的に提供することで解決できる。が、普通に lambda で書きたいですよね。

lambda での Closure と見かけ上同等の構文の実現

じゃあそもそも v1 では def apks(Closure) と書いてなかったのか?というと、ちゃんと(?) def apks(Closure) としていた。実は Kotlin DSL で closureOf などを使わずに lambda で書けている場合、この Closure 関数が直接呼ばれているわけではない。

Groovy では apks { ... }def apks(Closure) で動くし、この Closure を引数に取る関数が実際に呼ばれているんだけど、Kotlin DSL において apks { ... }getApks().invoke(...) の糖衣構文となっており、これは Kotlin DSL が定義する拡張関数によって実現されていた。

github.com

ということで差異は getApks().invoke(...) の糖衣構文であるところに由来していた。v1 では getApks() に NamedDomainObjectContainer がちゃんと指定されていたんだけど、2.0.0 ではリファクタリングの過程で def を使って動的解決に変更してしまったことが原因だった。 そうすると Object 型として認識されてしまう。そして最終的に Kotlin は「def apks(Closure) を呼ぼうとしてるけど型が一致してないよ」とエラーを吐くという感じ*1。 ref: v1 / v2

ということで、

  • apks(Closure) は Groovy で apks { ... } と書く用途
  • getApks(): <concrete type> は Kotlin DSLapks { ... } と書く用途

として動かせることがわかったので、修正した *2

setter property アクセス

Kotlin でも Groovy でも Property アクセスがサポートされているので、configuration ではメソッド呼び出しではなく代入文の書き方で表現できる

propName = "..."

という感じなんだけど、 Kotlin と Groovy の言語仕様の関係で、以下の記述が Kotlin DSL だと v2 で動いてなかった。

deploygate {
  userName = "userName"
}

Kotlin では Setter の可視性は Getter よりも広くなければならない。つまり private getter + public setter のような property は存在せず、この場合は setFoo(...) という呼び出しを強いられる。

Groovy はそんな制約はなく、private getter + public setter のような property でも foo = ... と書ける。

今回 2.0.0 では deprecated とした設定値を全て public setter で定義し、新しい設定値の property に delegate している。その結果、v1 ではただの public property だったものが Kotlin 上では property 扱いとならなくなってしまった。なお Groovy では動くので、Groovy 用の後方互換テストケースでは気づけなかった。

これは getter を定義するだけで修正できる

lambda や Closure を受け取りたい block (not DomainObject)

2022/10/25 追記。実行側のGradle バージョン依存の動作差異(Kotlin 1.3 compatibility)でした

github.com

2.0.0 では配布ページ(英名: Distribution) の設定について、distribution ブロックを用意して切り出した。

deployments {
  create("debug") {
    distribution {
      ...
    }
  }
}

これは Kotlin DSL だと最初の項 lambda と Closure の型変換 と同じ理由で、そのままでは動かない。この distribution は NamedDomainObjectContainer ではないので、invoke による補助が使えない。下記のように closureOf + 型指定でも動くけど、型を明示的に書いてもらうと今後のアップデートに支障が出るので正直避けたい。

deployments {
   create("debug") {
    distribution(closureOf<Distribution> {
      ...
    })
  }
}

さて、Kotlin DSL で推奨されている org.gradle.api.Action にすれば動くんじゃない?って思ったけど今度は Groovy 側で落ちるようになった。caller (owner) が Distribution lambda の this になってしまって見つからないらしい。

  • Marks a SAM interface as a target for lambda expressions / closures
  • where the single parameter is passed as the implicit receiver of the
  • invocation ({@code this} in Kotlin, {@code delegate} in Groovy) as if
  • the lambda expression was an extension method of the parameter type.

ドキュメントを見た感じ、delgate に差し込んでくれるんじゃないの?と思って悩んでたんだけど、そもそも Gradle Plugin 開発時に kotlin-dsl plugin (というか Kotlin + SAML w/ receiver compiler plugin) を当てないとここらへんの機能提供ができないっぽい。なんとなく Kotlin で Gradle 設定を書く方をKotlin DSLと呼ぶ印象があって、Plugin 開発側では何も考えていなかった。

試そうと思って Kotlin DSL を入れたら Kotlin コードから Groovy のコードが見れず、凄い長い戦いになりそうだったのでやめました。詳しい人教えてください。

蛇足

ここに Kotlin DSLDSL として動くように拡張関数が定義されており、かなり楽しい。 うーん、Configurable#invoke 生やしてくれないかなー

https://github.com/gradle/kotlin-dsl/tree/master/subprojects/provider/src/main/kotlin/org/gradle/kotlin/dslgithub.com

Action がなんで this を解決できるかについては SAM-with-receiver Kotlin compiler plugin を調べればOK。 kotlin/build.gradle.kts at master · JetBrains/kotlin · GitHub

そういえばGroovy -> Kotlin DSL への書き換えについては DroidKaigi 2019 で tnj という人が書き換えについて発表をしています。

スライド中で触れられている「Gradle のファイルっていつの間にか増えるよね」で増やした張本人は僕です。

speakerdeck.com

www.youtube.com

*1:悲しい?嬉しい? ことに IDE では型推論が動いてくれる

*2:ちなみに deployments は型を指定していた。なんでか覚えてないけど・・・

DroidKaigi 2019 スタッフ業

今年もスタッフでした。昨年の致命傷はこちら。

jmatsu.hatenablog.com

今回は

  • 採択後のスピーカーとの各種やり取り
  • タイムテーブル周り
  • アプリなどで使うAPIの作成
  • 公式アプリのメンテナー(特にCI)
  • 前日設営配送周り
  • Day1 のホール周りの下拵え(圧倒的 keima さんと hidey さんによりホール設営自体は全てやってもらいました。感謝。)
  • パーティー前移動作戦本部
  • セッション部屋リーダーの補佐
  • ほんのちょっとだけセッション部屋の司会
  • 遊撃手
  • ネットワーク(全く稼働できず)

今年は例年の致命傷を避けようとして結果即死した感じです。めっちゃミスしました。本当にすみません。

本業は同僚全員凄く理解のある人たちで助かりました(去年もですよ)。本当にありがとうございます。ただレビューや問い合わせなど自分以外の人がロックされてしまうタスクを優先しつつも、甘えすぎてもいけないので普通に開発をしたりとかなり忙しい日々でした*1

副業も最高に理解があって、いきなり無理を言って 1月中の稼働は結局0時間とさせてもらいました。本当にありがとうございます。

でも飲み会の回数は減らしませんでした。許してください。

採択後のスピーカーとの各種やり取り

今年は問い合わせのうちのいくつかを他の担当の人にディスパッチしつつ、基本的にプログラム用問い合わせMLに流れてきたものを拾って返していました。

それでも単一障害点と化したのは間違いなくて、返信が遅くなったり二度手間を取らせてしまったこともありました。不快な気持ちになってしまった方がいらっしゃいましたら、本当に申し訳ありませんでした。プログラム用のMLでもいいのでフィードバックを頂けると嬉しいです。

タイムテーブル周り

今年はタイムテーブルを @Reyurnible@satsukies に手伝ってもらいました。とても雑なお願いでシュッとやってくれてありがとう。戻ってきたときにGASでverificationが書いてあってとても感動しました。

さて、今年も「XXXとYYYを聞きたいのに被ってる〜〜〜!」という声をいただきました

わかる。頑張ってこの世に存在できるインスタンス増やしてください。

これは本質情報なのですが、8インスタンスあれば全てのセッションを聞きつつ、codelabsやスポンサー巡りができます。

Day1 ホール直後の移動問題 + Day1 パーティー前の移動問題

さて、昨年来た方は Day1 ホールセッション後や Day1 パーティー前の移動の惨事を覚えていらっしゃるかと思います。あれはひどい事件でしたね。

今回はそれぞれに対応をしています。一応うまくいったと思います!

Day1 ホール直後の移動問題

最初のウェルカムトーク、ホールAのセッションを終えたときの開放部屋調整を行っています。具体的には去年と異なりホールBを使えるようにし、5F で開放する部屋も減らしました。

さらに急遽、ホールAの最初のセッションを同時通訳にしてもらいました*2。元々同時通訳は完全に Room 3 だけの予定だったのですが、やはり最初のセッションは日英どちらの方も楽しんでいただきたく、僕の独断と偏見で同時通訳対象セッションをバチコーン!しました*3。発表されたTakuma さん、本当にありがとうございました。

droidkaigi.jp

この午前の構成ですが、僕の独断と偏見をそれっぽく解説すると

  • 今年はAACやマルチモジュールの応募が多い
  • それに伴う DI やテストの偏移についての話題が多い
  • AAC に関する知識が熟成し始めている

という背景を感じてまして、

  • DI on multi-modules
  • Build optimization
  • Navigation Component from AAC
  • AAC with testing

を主題とするセッションで構成することで、テーマ感をある程度持たせることができたのかなと思います。多分。

Day1 パーティー前の移動問題

  • Day1 最後の方のセッションを変則にし、同時に終わる部屋数を減らす
  • ホールで Fireside Chat を開き、移動を促す
  • 先んじてホールでウェルカムドリンクを配れるように業者(ビヨンドさん)の方にお願いする
  • Fireside Chat とウェルカムドリンクを踏まえたホールレイアウトを考える
  • keima 神による誘導

ということを今回は計画していました。

とはいえ僕がやったのは「関係各所の人をざっと集めまして、こんな感じの戦略で1Fに人を流していきたい、宜しくお願いします!」というざっくりとした方向性の提案だけで、実際に Fireside Chat を企画したのはcodelabs班だし、ウェルカムドリンクやバリスタさんのコントロールは全て飲食班、keimaさんはkeimaさんだし、ズラした枠にうまくセッションを当ててくれたのは僕以外のタイムテーブル班、展示ルームのコントロールはスポンサー班って感じでした*4。本当にありがとうございます。もちろん来場者の皆さんのご協力があってこそでしたので、その点も深く感謝しています!

APIや公式アプリに関して

皆さんコントリビューションありがとうございます! @takahirom さんを始めとしたコアメンバーがコントリビューションしやすいような形で整えてくれて、本当にかっこよかったです。

CIについてはどっかで発表しますが、急ぎでないときは CI やプロジェクトに依存しないように書いていたので、大部分が皆さんのプロジェクトでも動くと思います。ぜひ感想を聞かせてください。CircleCI v2.1 にするPRは後で投げます。CircleCI Orb化や Bitrise Step化も視野に入れてます。

ちなみに bot名に DroidKaigi と入れなかったことにはちゃんと理由があって、もし token を使われて罵詈雑言などを書かれた場合などにヒッジョーに面倒臭いからです。その点、僕のbotであれば(全く良くはないんですけど)まだ被害が小さいので。でもアイコンはいらすとやの最高のアイコンですよ。 (cc しほちゃん)

遊撃手

ショートではない。僕はファーストが好きです。

英語

今年も Global 班(メンションは english) という班がありまして、翻訳や proofread をお願いしてました。駄文を投げるとキレイになって返ってきて最高でした。

各セッションの英語タイトルは僕が一通り訳して、Global班に推敲してもらいました。皆さんの思惑と違うものがあったら本当に申し訳ありません。

やはり難しかったのが「投稿者がタイトルに含めたモチベーションと意味」をどれだけ維持できるかで、例えば @yanzm さんの DDD の戦術的設計 という言葉は明らかに DDD 由来なので、エヴァンス本を引っ張り出して来て訳の参考にしたりしました。他にも @shiraj_i さんの How about reviewing your Android Studio settings? は「何回かしらじさんの英語発表聞いてるけど、How about ~ って結構言うし、この言い方しそうだなー」と思いながら訳しました。

嬉しかったこと

  • 問い合わせしてくれた人たちが現地で「回答(調整)ありがとう」って言ってくれた
  • 前職(Quipper)のフィリピンの元同僚や入れ違いで入ったエンジニアが来てくれて、話す機会が取れた
  • アプリのコントリビューターから声をかけてもらえた
  • コーヒーが美味しかった
  • こそこそしてたらウェルカムトークの司会から今年は逃げられた

P.S.

いま家にニトリのポールハンガーが25個あって威圧感が凄いです。(画像のダンボールの陰に同じ量のダンボールがいます)。少しの間、食費のかからない25個と1人暮らしです。

f:id:jmatsu:20190210132451j:plain

*1:スポンサー企業の1つであり、CEO はスタッフ&スピーカー

*2:Global班、通訳の方、本当にありがとうございます

*3:ここが日本語または英語のみだと、聞けない言語の方の「次セッションに早く行きたい欲」が増強されすぎるのではという懸念もあり、同時通訳にすることで解消を図りました

*4:書きながら、自分で何もしてないことがわかってウケる

buildSrc や Gradle Plugin の開発のために Debugger を当てる

buildSrc 内のソースや Gradle Plugin の開発中でも Debugger を当てたいときはあると思います。

./gradlew --stop
./gradlew <any task> -Dorg.gradle.debug=true --no-daemon

非デーモンのデバッグモードで Gradle を立ち上げると、Debugger Attach 待機状態になる。デフォルトのポートは 5005。

IntelliJ の Run Configuration から Remote を新規作成し、デフォルトの設定で繋がる最高。

f:id:jmatsu:20190129211948j:plain

Gradle Plugin 開発の場合は大体 Project Evaluated のタイミングで終わってしまうので、Breakpoint は Debugger を Attach する前につけておきましょう。

pre-Lolipop でも TextView に icon tint を書けたい

MaterialComponent 対応をしていて、menu iconなども全部 theme baseのカラーリングにリファクタリングしている。

その中に pre-Lolipop でも TextView のicondrawable にtintが効かないというものがあったので、以下の方法で対応した。

import android.content.Context
import android.os.Build
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.widget.TextViewCompat
import com.google.android.material.theme.MaterialComponentsViewInflater

class LayoutInflater : MaterialComponentsViewInflater() {

    // pre-L cannot apply tint color for text view drawable
    override fun createTextView(context: Context, attrs: AttributeSet?): AppCompatTextView {
        val textView = super.createTextView(context, attrs)

        // throwable をsuppress するだけのtry-catchを別で書いている
        trySafely {
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                val drawables = textView.compoundDrawables

                if (drawables.all { it == null }) {
                    return textView
                }

                val ta = context.theme.obtainStyledAttributes(R.styleable.AppTheme)

                val color = ta.getColor(R.styleable.AppTheme_drawableIconColor, -1)

                ta.recycle()

                if (color == -1) {
                    return textView
                }

                val newDrawables = drawables.map {
                    if (it != null) {
                        val wrapped = DrawableCompat.wrap(it)

                        DrawableCompat.setTint(wrapped, color)

                        wrapped.setBounds(0, 0, wrapped.intrinsicWidth, wrapped.intrinsicHeight)
                        wrapped
                    } else {
                        null
                    }
                }

                TextViewCompat.setCompoundDrawablesRelative(
                    textView,
                    newDrawables[0],
                    newDrawables[1],
                    newDrawables[2],
                    newDrawables[3]
                )
            }
        }

        return textView
    }
}

公式がやってない辺りにちゃんと理由がありそうで、とても気になる。なんでだろう。

2018 年の振り返り

自分用のメモも兼ねて

f:id:jmatsu:20190103152041j:plain

人生

内容
1月末 Quipper を退職
2月頭 DroidKaigi
2月~ スノボいきまくる
2月~ 業務委託を2件持ってみて、忙殺される
4月頭 DeployGate に入社
5月 会社のお金で I/O
8月 KotlinFest のお手伝い
8月 我が家納骨所になる*1
10月頭 会社のお金で Kotlin Conf (デンマーク経由・滞在)
11月末 JAL 修行終了 (会社のお金ではない)

正直大体の月で忙殺されていた気がするけど、原因を具体的に覚えてない事項が多い。

2月から週2~3 の業務委託を2件契約して週5~6 で働いた時期がちょっとだけあったけれど、3日ごとくらいにコンテキストスイッチが必要になるし、日によっては1日でコンテキストスイッチを頻繁に考える必要があった。
当然効率は一定以上上がらないし、この状態で「自分から球を拾いに行くスタイル」で働くことは(少なくとも自分には)かなり厳しいことがわかったのでもう二度とやらない・・・という学びを得た

Backend (本業)

  • GCM -> FCM 移行
  • クレジットカード支払い周りの再設計
  • Group のクレジットカード支払い対応
  • サーバーサイドのローカル環境構築の自動化
  • Enterprise における SAML 認証 (テスト運用中)

1個1個のタスクが大きくて、数にしたらあんまりなかった。

Android (本業)

  • GCM -> FCM 移行
  • CI チューニングとジョブの整備
  • Crashlytics などの解析系導入と解析結果の GitHub Issues への連携
  • WebTranslateIt による翻訳文書の管理
  • svg -> vector drawable, optimized png の自動インポート
  • Ribbonizer や git-pr-release などによる一人でもリリース間違えないもんリリースフローの整備
  • Detekt, ktlint, Android Lint × Danger による一人でも寂しくないもん開発環境の構築
  • Re-architect
  • AndroidX と Material Components 対応 (未リリース)

弊社ァの Android リポジトリは独立時点で新しくしたことやそもそもそんなアップデートをしていなかったこともあって、入社時点で PR/Issue が合計で9個しかなかった。 今確認したら 330 までいったので、なるほど。という気持ち

趣味

今年一番気に入った日本酒はこれ、獅子の里。愛山特有のすっきりした酸味と甘味があって、口の中で転がすと本当にいちごのような香りがして半端なく美味しい。

でもちょっと体が心配になってきたので、量を減らそうと思います・・・

英語力

時々フリートークでDMM英会話をしているけど、前職 *2 からあんまり伸びてない気がする。ただ周りの英語話者(non-native含む)には今も恵まれていて、推敲含めて教えて貰えることが多い環境に身を置けていて大変ありがたい。

学部生の頃に TOEIC 315 点しかなくて留年の危機 *3 に陥ったし、入試や院試 *4で苦しんだけど、今はさすがに上がってるやろ〜〜ってことでTOEICを受けた。

f:id:jmatsu:20190103144915j:plain

英語を仕事で使う身としては圧倒的に低いけど、元が低いこともあって2.5倍になった。やはり「TOEICの点数をあげるには最初に低い点数をとればいいじゃない」説は正しい。

みんなもまず300点くらいを取ることをオススメします。その後900点を超えたらなんと3倍です。

2019 年での目標

  • 中華と和食が多いので、イタリアンのレパートリーを増やそうと思います。何か食いたいものがあったら言ってください。作れるようになります。
  • 今年はインフラやBackend周りを重点的にやろうと思います。
  • いっそ日本酒になりたい

*1:倉庫に本来戻すはずのバックパネルの骨が、ケースの破損を理由に今も我が家に鎮座している

*2:Quipper は外資(?)企業で英語を話す機会や読み書きの機会が大量にあった。ただし話す機会については逃げることが可能(要出展)で、少なくとも事前準備できるケースがほとんどだったので周りから助けられながら生きていた。

*3:当時の東工大は英語4という2年後期の英語科目の認定にTOEICの点数などを使う。今は水準が上がってるらしいが、自分の代はTOEICが500点あれば問題なく単位が取れるという緩い世界だった。つまり315点じゃ単位が取れなかった。もちろん別の講義で単位をとればOK。

*4:TOEICの点数は院試時に英語の点数として反映されていたはず

2019年を振り返って

セブンからの帰り道、しほちゃんちの鍵を自分の家のオートロックに差し込もうとして刺さらなくて困惑しながら2019年を迎えた。

上の階の人がハッピーニューイヤー!おやすみ!って叫んでた。

むしろ食われろ、餃子に

http://pbs.twimg.com/media/B7ZhPFgCMAAHw8W.jpg

http://www.anime-line.com/animes/156/stories/2982

今年もやってまいりました、SHIROBAKO Advent Calendar 2018 4日目です。

adventar.org

さて、SHIROBAKO 第12話、「えくそだす・クリスマス」の回を覚えているでしょうか?

作中で制作されているアニメ「えくそだす」の最終回を仕上げる重要な回であり、杉江さんによるプロフェッショナルな仕事を見ることができます。

杉江さんへの愛については 2016年のAdvent Calendar より、konifar さんによる SHIROBAKO12話の杉江さんが好きなのでただただまとめておきたい を御覧ください。「わかる」しか感想が出てこないので、この点について僕から言うことは何もありません。

konifar.hatenablog.com

しかしこの回には非常に特徴的なキーワードが出てくることをご存知でしょうか?開始5分頃の会話に出てきます。

興津さん「高梨さんは矢野さんを送っていったあと連絡が取れませんでしたが、先程、餃子を食べてから午後には戻る。とのメールが来ました」

本田さん「餃子?なんで?」

興津さん「せっかくだから、だそうです」

本田さん「むしろ食われろ、餃子に」

そうです、餃子です。餃子は美味しいですよね。14話にも出てくることを考えれば、そこらへんのモブよりも餃子の存在感は強いと言えるでしょう。

https://img.gifmagazine.net/gifmagazine/images/70409/original.gif

https://gifmagazine.net/post_images/70409

ということで、宇都宮餃子の町「宇都宮」で育った僕がオススメの餃子を紹介します。ここから SHIROBAKO の話は一切出てきません。

吉祥寺 - みんみん

みんみんはあの松亭がある吉祥寺のハモニカ横丁内に存在する中華料理屋です。

retty.me

なかなかに大ぶりな餃子です。皮は少し厚めでモチモチしつつも くどい弾力はなく、加えて肉と野菜のバランスの良い餡を味わうことができます。

また名物のあさりチャーハンも最高に美味しいです。焼き餃子と一緒に食べましょう。結構量があるので二人でいって餃子をシェアするといいかもしれません。

新橋 - 一味玲玲

2つ目は新橋の中華料理屋、一味玲玲です。

retty.me

15種類を超える餃子を焼き・水・蒸しの3種類の調理法から選べます。

オススメはなんといってもレモン餃子の焼き。レモン果肉の酸味やレモン皮にあるほのかな苦味が良いアクセントになり、ビールが無限に飲めます。

自分の好きな餃子のタネと調理法を見つけてみるのも楽しいかもしれませんね。

宇都宮 - 正嗣

「地元の人でも食べるお店へいきたい」と聞かれることがあります。ただよく驚かれるんですが、地元の友人に聞いても宇都宮民でもあまり餃子専門店に行きません。 *1

そんな中でも自分や地元の友人が行ったことのある餃子専門店が「正嗣」です。*2

www.ucatv.ne.jp

メニューは焼き餃子と水餃子のみ、また持ち帰りだと冷凍餃子が購入できます。ライスやビールはありません。なぜならここは餃子専門店だからです。しらんけど。

1枚210円という安さのため、たこ焼きを食べる感覚・セブンでコーヒーを買う感覚で立ち寄り、焼き1水1を頼んでシュッと食べましょう。

野菜多めの餡で皮は薄く、何個でも食べられるタイプの餃子です。リピーターが多いようで、友人の中には実家を出てからも通販で買ってる人もいるようです。

宇都宮 - 来らっせ

餃子を色々食べたい・・・というあなたには「来らっせ」というお店をオススメします。

retty.me

宇都宮には宇都宮餃子会と呼ばれる協会があり、来らっせはその協会の中でも有名な店舗の餃子を一箇所で楽しめる融合店舗になっています。また宇都宮餃子というワードとともにテレビ(首都圏しか知らない)で取り上げられるお店は大体この協会に所属しています。

これらの餃子屋は行列のできるお店もあり、全てを回ることはもちろんのこと、一部の店舗をはしごすることすら難しかったりします。それを1店舗で楽しめるというのはかなりの良さじゃないでしょうか?まあいったことないんですけど。

ちなみに上で紹介した正嗣はこの協会に所属していません。

*1:宇都宮は餃子の町やカクテルの町、日本一景観の悪い駅など様々な肩書を持ちますが、その中で一番「わかる〜〜〜」と思うのは日本一景観の悪い駅という肩書だけです(個人の感想です)

*2:高校のすぐそばにあったので。家族で餃子専門店にいったことは一回もないです