がんばるぞ

がんばります

2019年まとめ

主な出来事

(やっぱり技術的な挑戦はあまりしてないな)

今年買った本

良かった本だけ掲載。

ザ・ファブル」と「悪魔のメムメムちゃん」以外の漫画は全てカバレッジを上げている期間に読みました。精神を病まないようにすることに必死でした。

うーん、技術書を全く読んでない。これはひどい

あっ、大事な本を忘れてました。
僕も寄稿させていただいたみんなのPHPは最高なので買ってください!

2019年の雑感

2019年、色々ありました。

技術的に大きく進歩した実感はあまりないけど(遊びすぎた)人間関係がすごく充実した良い一年だったと思います。

知り合いが増えた

一番の変化はやはり知り合いが増えたことでしょうか。
hamacoさんのおかげもあり本当に知り合いが増えた。死ぬほど増えた。
去年は雲の上だと思っていたような人ともTwitter上で会話が出来るようにもなりました。
本当に信じられない変化ですね。

心を許せるレベルの知り合いも複数人出来ました。
すごい幸運。ラッキーボーイ。みなさんいつもありがとうございます。

そして、勉強会などで会ったことのない人から「Twitterで顔だけ見たことあります」みたいなことを言われるようになった。
どうかしてる。

コミュニティは本当に大事だなと実感した1年だったので、来年も無理のない範囲でコミュニティに貢献できたらなと思ってます。

みんなのPHPに寄稿した

商業誌ってずっと目標にしてたんですよね。まさかこんなに早く関わることが出来るとは。 みんなのPHP、もっと売れるといいな〜〜!

次は単著出せるようにがんばるぞ〜。

遊びすぎた

本当に遊びすぎた。 仕事でカバレッジを20%から90%に上げたりはしたけど、やれば誰にでも出来ることだし、何にも挑戦してなくてヤバい。

未熟さを思い知らされた

すごい人ってすごくて(語彙力)、会話をするたびにレベルの違いを思い知らされます。

中でも印象に残っているのはDDD Meetupの懇親会の時のことで、すごい人たちが繰り広げているモデリングの議論にまっっっっっったくついていけなかったことです。

レベルが高すぎるゆえに質問することすら出来なくて、とてつもない悔しさと「この人たちスゲェ」という興奮が綯い交ぜになった感情を抱きました。

このように、すごい人たちに囲まれていると「このままじゃヤバい」という感情がムクムクと湧いてくるので、来年はネタキャラとしてだけではなく、Webエンジニアとしてもみんなと会話が出来るようにならないとなーと思っています。
とくに今年はみんなと知り合えた嬉しさからか遊びすぎた(はしゃぎすぎた)ので、来年は遊びはほどほどにしてたくさん勉強しようと思います。

カバレッジを上げて燃え尽きてる場合じゃない。

来年の抱負

  • Laravel JP Conference 2020やるぞ!
  • 設計勉強するぞ!
  • 会社のサービスを伸ばすぞ!
  • フロントエンド方面も勉強するぞ!
  • 個人でWebサービスリリースするぞ!
  • 勉強するぞ!
  • 勉強するぞ!
  • 英語勉強するぞ!
  • 音楽もやるぞ!
  • 勉強するぞ!
  • 実装速度を早くするぞ!

やるぞ〜〜〜〜〜〜〜!!!!!!!!!

*1:僕よりも前から焼肉の人

*2:由緒正しい焼肉の人

*3:リファクタリングコストの都合上、不本意な(中途半端な)実装で妥協せざるを得なかったクラス

PHP Conference Japan 2019で登壇してきました

かなり時間が経ってしまいましたが、PHP Conference Japan 2019 にて登壇してきました。

togetter.com

20%もなかったカバレッジを90%まであげたので、そのためにしたことの話をしました。

動画はそのうちYoutubeに上がるのかな?上がったらこの記事に貼っておきます。 動画あげてもらいました! www.youtube.com

この記事は登壇後記という体のただの乱文です。

ポエム

いやぁ、普通に疲れました。
登壇が終わってから、ブログを書いてる今この瞬間も完全に燃え尽きてます。

一つのエンドポイントにテストを追加するとだいたい0.04%〜0.08%くらいはカバレッジが上がってくれるんですが、 途中 0.01%〜0.03%しかカバレッジが上がらないみたいなことが連発していた時はだいぶ精神的に追い詰められました。

けどなんとか登壇までに90%まで上げることが出来てよかった。

カバレッジをあげたかった理由は登壇の最初でも話したんですが、それ以外にも 「テストがあれば防げたようなバグを僕がデプロイしてしまったから」ってのがあるんですよね。

C0レベルのテストでも防げたようなしょうもないバグで、でもめちゃくちゃ重要な機能にバグを放り込んでしまって めっちゃくちゃ情けなかったんです。

この情けないミスの償いと、同じミスを僕以外のエンジニアにさせないためにカバレッジを上げなければと強めに決心しました。

コツコツと自分の関わった範囲にテストを追加していくような手段も取れたんですけど、 派手にカバレッジを上げ、それをネタに登壇することで広報的な効果も追加出来るんじゃないかなーと思って、一気に90%まで上げることにしました。

ほら、テストってただでさえユーザーに対して直接価値を届けられるようなものではないじゃないですか。(主観)
なので、テストに大きくリソースを割くことに抵抗というか葛藤があったんですが、広報的な効果を追加すれば会社的なメリットも増えるし、まぁいいんじゃないかなーと。

ですが実際に登壇した結果、広報的な役割をしっかり果たせたのかというと

  • ポジティヴな印象を与えることが出来たのかわからん
  • PHP界隈の話題にすることが出来なかった

という点でかなり微妙なところではあるので、もうちょっと技術的に面白い話が出来たらよかったかなぁという反省があります。

カバレッジを上げて得たもの

チームメンバーへの感謝の心

僕がテストを書くことだけに集中出来るようにチームメンバーのみなさんがだいぶ気を使ってくれたので、本当に感謝しています。
具体的には、ほぼフルリモートで働くことを許可してくれたり、なるべく僕にテスト以外の作業が発生しないように配慮してくれたりですね。
みんなの配慮がなければ絶対に登壇までに90%は間に合わなかったと思います。

この場を借りてお礼を言います。ありがとうございました。

デプロイの安心感

C0レベルのテストは90%の箇所に書かれているので、とりあえず正常系であればテストが通っていればほぼほぼ動くのではって感じです。
ただ、実装をみて仕様を想像しながらテストを書いてるだけなので、漏れてるケースはちょこちょこありそうだなー。

カバレッジを追い求めることの無意味さ

おい!!!!!!!って感じなんですけど、カバレッジを追いかけるのはマジで虚無だなという感想を得ることが出来ました。

あ、いや、今回カバレッジを上げたが無意味だったという話ではないです。念の為。
今回カバレッジを上げたことは大きな意味がありました。が、カバレッジをKPIにする必要はないなという話です。

登壇の最中にも軽く話したんですが、弊社のサービスの場合は75%や80%を超えたあたりでだいたい必要そうな箇所にはテストをかけたなーという感覚があって、 それ以降は登壇のタイトルで90%って言ってしまったから仕方ねぇって感じで、「書かなくてもいいかなー」って感じのユニットテストをもりもり追加するような感じになっていました。

おそらくサービスごとに適切なカバレッジがあって、それは必要な箇所にテストを書いた結果自然と導き出されるものなので、カバレッジをKPIにしてテストを書いていくと不必要なテストが発生するんじゃないかなと思います。

みんなカバレッジとか気にせずにちゃんとテスト書いていこうな。

とはいえ、ローカルのPHPを7.4にあげてみた時にバグを発見してくれたのは「このテスト書かなくてもいいんじゃないかなー」って思って書いたユニットテストだったりしたので「このテストは必要ない」って判断するのめっちゃむずいよねって感じなんですが・・・。

また別の話ですが、テストは最終的には負債でしかないっていう意見もあって、僕も割と共感してます。

PHPは動的型付言語だし型の制約が強いわけではないしって理由でテストを書かないという選択をするのはだいぶ難しいと思うんですが、テストを書かなくて良いようなコードをかけたらよいなぁと思ってます。

PHPStanやPhanという静的解析がだいぶ強くなっているので部分的には可能かなぁ、どうだろう。

テストの責務についての考え方

Unitテストや機能テスト、受け入れテストでそれぞれのテストが担保すべき内容って違うんですよね。

機能テストで実行されているコードはUnitテストが必要ないのかというと絶対にそんなことはなくて、 テストの関心ごとが違うからそれぞれテストしないといけないと思うわけです。
機能テストの関心ごとじゃないところまで機能テストで担保しようとするとテストが大きくなりすぎちゃいますしね。

漠然と今までも理解していたんですが、今回死ぬほどテストを書きまくった結果そこらへんの考えがより明確に(深く?)なったので、どこかで改めてまとめたいなーと思ってます。

おわりに

はい、こんな感じかなー

テストは書いたので、次はこのテストたちを武器にリファクタリングに励みたいと思います。

おわり

PHPカンファレンス沖縄2019のLTでミューテーションテストについて話してきました

PHPカンファレンス沖縄2019でLTをしてきました。

togetter.com

speakerdeck.com

LTの内容はミューテーションテストの基礎的な概要を紹介するといったものだったのですが、5分という時間の制約上伝えられなかったことがたくさんあるので、この記事で補足を兼ねて解説しなおしたいと思います。

※この記事はあくまで僕の解釈です。一般的な解釈と異なる記述がある可能性があります。

ミューテーションテストとは

ミューテーションテストとは、我々が実装したアプリケーションコードの一部を書き換え、書き換えたコードに対してテストを再度実行することでテストの品質を測ろうというものです。

簡単に表現すると「アプリケーションコードに変更が加わったのに、既存のテストがパスするのはおかしいんじゃないか?」という視点で品質を評価するということだと思います。要するにテストコードに対するテストですね。

ミューテーションテストが必要になる理由

一般的なテストコードは、我々が実装したアプリケーションコードに対して実行し、アプリケーションの品質を保証する(したい)ものだと思います。

これはとても重要なもので、テストコードを書くことによって

  • アプリケーションの品質の維持
  • 安全なリファクタリングの実現
  • 実装時に見逃していたバグの発見
  • etc

など、いくつかのポジティブな効果が期待できます。 *1

一方でそれらの効果を期待するためには「品質の良いテストコードである」ということが求められるかと思います。しかし、テストコードの品質を数値化するということは非常に難しい課題です。

広く知られる指標としてコードカバレッジがありますが、これはテストでどれだけのアプリケーションコードが実行されたかということを示すだけで、テストコードの品質についてフィードバックを得られるわけではありません。*2

そこで役に立つかもしれないのがミューテーションテストと呼ばれるものです。

どうやっているのか

先に述べたように、アプリケーションコードを変異(ミューテート)させ、それに対して再度テストを実行することでテストの品質を評価します。

どのような変異を起こしてくれるのかというと、これは各テスティングフレームワークによって異なると思います。

PHPにはinfectionというテスティングフレームワークがあり、公式ドキュメントで様々なミューテーター(変異の種類)が紹介されています。

ミューテーターはかなり多く用意されているので、少しだけ紹介すると

説明 元コード 変異後
配列に対する操作の変異 $a = array_filter(['A', 1, 'C'], 'is_int') $a = ['A', 1, 'C']
論理式の変異 $a < $b $a <= $b
論理式の変異 $a < $b $a >= $b
Loopの制御文の変異 break continue
例外処理の変異 throw new Exeption new Exception
例外処理の変異 try {} catch (Exception $e) {} finally {} try {} catch (Exception $e) {}

など、様々な変異を起こしてくれます

例えば、以下のようなコードがあったとします。

<?php
class Number
{
    private $value;

    public function __construct(int $value)
    {
        $this->value = $value;
    }

    public function isSmallerThan(int $value): bool
    {
        return $this->value < $value;
    }
}

isSmallerThan というメソッドは、与えられた数値よりも $this->value の値の方が小さければtrue、そうでなければfalseを返すという簡単なメソッドです。

そして、このコードに対するテストコードが以下です。

<?php
use PHPUnit\Framework\TestCase;

final class NumberTest extends TestCase
{
    public function testIsSmallerThan()
    {
        $number = new Number(15);
        $this->assertTrue($number->isSmallerThan(20));
    }
}

15のNumberの isSmallerThan に20の数値を渡しています。
もちろん15は20より小さいのでtrueを返し、テストはパスします。

この状態でinfectionを使いミューテーションテストを実行してみると以下のような実行結果が出力されます。

--- Original
+++ New
@@ @@
     }
     public function isSmallerThan(int $value) : bool
     {
-        return $this->value < $value;
+        return $this->value <= $value;
     }
 }

この例では <<= に変異させても既存のテストが全てパスしてしまうこと、つまり境界値テストが足りていないことがわかり、(ミューテーションテストから見た)テストの品質をあげる具体的なヒントを手に入れることができました。

このようにして、既存のテストに足りていないと思われるテストをミューテーションテストを通して知ることができるようになります。

課題

ここまでの話でミューテーションテストに対してかなり期待を持った方が多いのではないかと思います(多いといいな)

しかし、ミューテーションテストを実際に運用するとなるといくつか課題が浮かびます。

実行時間

ミューテーションテストは、かなり重い処理になります。 アプリケーションコードが多くなればなるほど多くの時間が必要になり、公式サイトにもアプリケーションの規模によっては数時間かかるかもしれないというような文言があります。

If you have thousands of files and too many tests, running Mutation Testing can take hours for your project.

これに対するアイデアとしては、masterブランチやdevelopブランチと差分のあるファイルにのみinfectionを実行するというものです。

$ infection --threads=4 --filter=$(git diff origin/master --diff-filter=AM --name-only | grep src/ | paste -sd "," -) --ignore-msi-with-no-mutations

この方法であればPRが大きくならない限りは現実的な実行時間でCI上でもミューテーションテストを実行することが可能になると思います。

ミューテーションテストの全ての指摘に対応するのはコストが高い

デフォルトの設定でinfectionを実行してみると、ちょっとしたコードでもなかなかの量の指摘が発生すると思います。

中には有益な指摘も当然ありますが、全てに対応するのはコストの割にはメリットが少なさそうだなというのが僕の感想です。

これに対する有効そうな手段はいくつかあると思います。

min-msiを調整する

msiは Mutation Score Indicatorの略で、ミューテーションテストのスコアです。 MSIは0%から100%までの値を取り、数値が大きければ大きいほどミューテーションテスト的に品質の良いテストということになります。

開発チームで許容出来る最低スコアを設定することで、全ての指摘事項に対応しなくてもミューテーションテストをパスすることが出来るようになります。

ですが当然全ての指摘の重要度が等しいわけではないので、有益な指摘を見逃している場合であってもmin-msiを超えているテストであればミューテーションテストをパスすることになるので注意が必要です。

不要なミューテーターを無効にする

infectionではミューテーターを細かく設定することができます。(https://infection.github.io/guide/profiles.html)

必要と思われるミューテーターのみ有効にすることで、ミューテーションテストの対応コストを調整することも可能です。 が、こちらも有益な指摘を見逃す可能性が発生することを念頭に置く必要があると思います。

おわりに

最近ミューテーションテストの存在を知り、個人で開発しているライブラリに対してinfectionを導入してみましたが、まだまだ検証が足りていません。 どこまでテストの品質が上がるのか、そしてどれだけ有効なのか未知数なので、もうちょっとしっかり触ってみたいなーというところです。 実際にミューテーションテストをゴリゴリ使っていらっしゃる方がいれば是非吉田あひるまでご連絡ください!

*1:テストコードの内容によってはむしろ技術的負債になることもありえますが、テーマから逸れるため割愛します

*2:もちろんテストされていないアプリケーションコードを把握できるというのは大きなメリットです。

「具体と抽象」という本を読んで、リスコフの置換原則が少しだけわかった気がした

読みました。

雑感

内容に関してはプログラミングの話はなく、我々人類にとって抽象化という行為がどれほど大切なものなのか、そしてどういう形で受け入れられているのかということを非常に平易な言葉で解説してくれています。

抽象化について何となくわかってはいたけど言語化していなかったことが、この本を読むことでいくつかスッキリできました。
またそれと同時に、抽象化についてよくわからないことにも新たに気づけたので、非常に良い本でした。

プログラミングをする多くの人に対してオススメできる本だったのではないでしょうか。

得たもの

リスコフの置換原則について、少しだけ理解できた気がしました。

まず抽象の性質として以下のものがあるとされていました。

  • 抽象は相対的なものである
  • 抽象は階層構造である

抽象は相対的なもの

人を抽象化すると哺乳類になり、哺乳類を抽象化すると生き物になります。 人からすると哺乳類は抽象ですが、生き物からすると具象になります。

つまり、概念を一つ切り取ってそれが抽象であるか具象であるかという判断は出来ないということです。

プログラミングで抽象というと、抽象クラスやインターフェースを思い浮かべることが多いと思いますが、それだけが抽象なのではなくて

具象クラスであっても継承などの相対関係が存在すれば、サブクラスにとってスーパークラスは抽象化されたものと捉えることが出来るのだなと考えました。

抽象は階層構造

抽象化とは具象から余計な特徴を捨て(捨象)、本質的な特徴だけを見る行為だと解説されていました。

つまり、上位の階層がもっている特徴を下位の階層は全て引き継ぐということであり、その逆はないということです。

僕はこの解説を聞いた時にリスコフの置換原則そのものではないかと感じました。

リスコフの置換原則

リスコフの置換原則は、サブクラスはスーパークラスと置き換え可能でなければならないというやつです。

非常に極端な例を出しますが、以下のようにSuperClassとSubClassがあった場合に、SayHiというクラスのrunメソッドにSubClassを渡せるわけですが、おそらくSayHiというクラスが予想している挙動にはならないでしょう。

<?php
class SuperClass
{
    public function hi()
    {
        return 'hi!';
    }
}

class SubClass extends SuperClass
{
    public function hi()
    {
        return ['hi!', 'hello'];
    }
}

class SayHi
{
    public function run(SuperClass $class)
    {
        echo $class->hi() . ' everyone!';
    }
}

このように、スーパークラスと置き換え可能ではないサブクラスは原則として良くないよというのがリスコフの置換原則です。

今までは「サブクラスが置き換え可能でない状態だと考慮しなきゃいけないことが増えて設計が複雑化しそうだし確かに良くなさそうだな」という程度の理解だったのですが

「抽象とは相対的なものである」かつ「抽象は階層構造で、上位階層の特徴を下位階層は受け継ぐ」という定義を明確に意識できたことで 「リスコフの置換原則に違反するということは、抽象と具象という関係の性質から大きく離れることになるのでかなり筋の悪い行為なのではないか」と思えるようになりました。

また、抽象と具象の関係性という非常に本質的な部分の話なので「原則」という言葉が使われているのだと理解しました。
(ちなみに日本語では原則ですが、英語のprincipleは例外はありえないという強い言葉のようです)

わからないと気づいたこと

抽象の階層構造ってすごく難しいな(=わからないな)と感じています。

人間と哺乳類、そして生物という抽象の階層構造は感覚的に理解出来るのですが、僕がモデリングする対象の中に抽象の階層構造を見つけることが出来るのかというと、うーん、もっと深く考えないと難しそうだなと思っています。

2019年のLaravel JP Conferenceで「抽象化って何?」という発表があったことを思い出したので、改めて見返してみましたがやはり難しいですね。

その発表の中で紹介されている思考と行動における言語という本を次は読んでみようかなと思っています。

読書感想文でした。おわり。

具体と抽象

具体と抽象

Englishman in New Yorkを耳コピしたのでメモ

www.youtube.com

かっこいいですね。

かっこいいので耳コピしました。

今まで耳コピしたものは、雑にコード譜を書いているだけだったのですが
これからは雑にコード譜を書いた後は共有までしてみようかなと思ったので、ブログにでも載せることにします。 著作権的に怒られたら消します。

そんなに音感は良くないので、合ってる保証はないですけどねっ

drive.google.com

Coverageの計測をxdebugからpcovに変えたら、CIの実行時間が5分の1になった

PCOVなるものを使うと、CIがめっちゃ早くなるという情報を得て、早速CIに導入してみました

pcovとは

超高速にCoverageの計測が出来るドライバーです。
こちら を確認してみると2019/1/16に初めてリリースされた、かなり新しめのプロジェクトのようですね

動作要件はPHP7.1以上です

インストールはpeclもしくはソースからビルド出来ます。僕はpeclでインストールしました。
詳しくはこちら

CI用Dockerコンテナの作り直し

今まではxdebugで計測していたので、その部分をpcovに変更します。
(CircleCIのconfig.ymlで直接xdebugのインストールしている人は適宜読み替えてください)

FROM php:7.3
# 中略
- RUN pecl install xdebug \
-  && docker-php-ext-enable xdebug
+ RUN pecl install pcov \
+  && docker-php-ext-enable pcov

そして、書き直したDockerfileをビルドし直して、DockerHubにあげておきます。

cd /path/to/docker
docker build -t {DockerHubのアカウント名}/php_for_circleci .
docker push {DockerHubのアカウント名}/php_for_circleci:latest

CircleCIのconfigを修正

イメージに先ほどのコンテナを指定しておき、テストの実行方法を指定します。

version: 2

jobs:
  test:
    docker:
      - image: {DockerHubのアカウント名}/php_for_circleci:latest
      # 中略
+     - run:
+         name: test
+         command: php -d pcov.directory=./ -d pcov.exclude=./tests vendor/bin/codecept run --coverage-xml

ポイントは、 php -d pcov.directory=./ -d pcov.exclude=./tests の部分で、 -d オプションでiniの設定をオーバーライドしてます。

pcov.directory は、カバレッジ計測対象のディレクトリを指定します。
ここが指定されていない場合は、カレントディレクトリからsrc、lib、appの順にディレクトリを探し、そのディレクトリ内のカバレッジを計測するようです。*1
つまりデフォルトの状態では、計測対象のディレクトリがsrcでもlibでもappでもない場合はカバレッジの計測をしてくれないことになります。

pcov.excludeカバレッジ計測から除外するディレクトリを指定します。
pcov.directoryにテストコードのディレクトリが含まれている場合は、そのディレクトリのカバレッジを計測してもマシンリソースの無駄なので除外します。

僕は実行時のオプションでディレクトリの指定をしていますが、php.iniに設定を書き込んでも問題ないと思います

おわり

なんとこれだけのステップで導入出来ます。
実質pcovをインストールするだけですね

僕の場合は、ユニットテストが5.5minほど掛かっていたのですが、1minまで短縮されました。
よかったですね。

牛肉について

先日ツイッターのTLで自由研究LTというイベントを見かけて、こんなツイートをしました

ということで、自由研究として牛肉について少しだけ調べたので、結果をまとめました。

和牛って?

和牛とは、以下の4種の牛のことを指す

2003年の段階では、日本で食される品種は黒毛和種が58.7%と圧倒的なシェアを誇っており、それ以外の3種は全て合わせても全肉牛のうち2%程度のシェアとなり 日本で食される高級な和牛のほとんどは黒毛和種となっていることがわかる。*1

また、残りのシェアはホルスタイン種という乳用種が17.5%、ホルスタイン種と黒毛和種の交雑種が21.6%、その他0.2%となっている。

A5って?

A5とは、牛が市場で買取価格のランク付けをされる際に用いられる記号である。

A5ランクを獲得することで、その牛は高く買い取られることになる。
Aと5でそれぞれ評価のポイントが違い、Aは歩留まりで、5は肉質の評価となる。
詳しくは後述するが、A5ランクとはつまり、 「たくさん肉が取れて脂肪がたくさん含まれている牛」 のことだ。

歩留まりについて

歩留まりとは 「牛一頭につき、どれだけの肉が取れるか」 という基準のことである。
多く取れる方からA、B、Cと3段階で評価される。
牛乳の生産を目的とされる乳用種などはだいたいがBかCランクとなり、Aランクを取ることができる牛は肉用種であることがほとんどである。

肉質の部分について

肉質の良い方から5、4、3、2、1と5段階で表される。
また肉質と一言でいっても、評価ポイントはいくつかある。

  • 肉の色艶
  • 肉のキメや締りの良さ
  • 脂肪交雑(いわゆるサシ)の量
  • 脂肪の色艶

これらを総合的に評価して結果を決めることになる。
これらの評価基準の中で注目したいのが脂肪交雑(以降サシ)だ。

サシについて

サシとは、筋肉の中に含まれる脂肪のことである。

サシの量はBeef Marbling Standard(以降BMS)という基準によって評価され、 ナンバー12からナンバー1の12段階があり、数値の大きい方がサシが多く評価が高いということになる。

肉質の評価で5を獲得するためには、BMSナンバー8以上を獲得する必要があるが、ナンバー8の牛肉のサシの割合はどれくらいかというと、なんと 5割を超える。

実はBMSが要求するサシの割合は年々増加しており、1996年の段階ではBMSナンバー8に必要なサシの割合は30%強であったのに対し、2004年の段階で50%を超えている。
たった8年の間に20%も増加していることがわかる。 *2

サシが増えることで肉の風味が良くなるが、ある一定の割合を超えると、いくら増えても味に対して ポジティブな効果が期待できない 事が指摘されている点に注意が必要だ。

なぜ黒毛和種がこんなに多いのか

乳用種のホルスタイン種と、ホルスタイン種と黒毛和種の交雑種を抜いた、和牛だけのシェアを計算すると、9割以上が黒毛和種ということになる。

なぜこんなにも黒毛和種がシェアを取っているのかというと、理由はサシにある。

肉質の評価基準でサシについて触れたが、和牛4種のうち、最もサシがつきやすいのが黒毛和種なのだ。

牛の買い取り価格を上げるためにはA5ランクを獲得する必要があるが、黒毛和種以外で現在のBMSナンバー8以上を取ることは難しいため、 黒毛和種以外を育てても儲けにくい という背景があるのだ。

まとめ

昔のA5に比べて現在のA5の肉はとっても脂肪が多い!

A3やA4くらいの方がおいしそうな気がする!

黒毛和種以外も食べてみたい!