がんばるぞ

がんばります

コンピュータシステムの理論と実装 Chap1

www.amazon.co.jp

最近この本をやり始めたのでメモ

1章概要

ブール理論を理解し、本書から提供されているハードウェアシミュレーターを用いて数種類の論理ゲートを実装する。

論理ゲート

ブール関数を実装した物理デバイスのことらしい。が、実際に物理デバイスを作る必要はなく、ハードウェアシミュレーター上で論理ゲートを実装すればOK。

ブール関数とは And とか Or とか Not のように、 n個の入力値を元に新しいブール値を出力するような関数のこと

And だったら2つの入力値が共に True であれば True を出力し、それ以外であれば False を出力するし、 Not であれば1つの入力値を反転させた出力をする。
出力値は1つとは限らず、例えば Demultiplexor と呼ばれるブール関数は複数の出力を持つ

論理ゲートの実装

Nand (=not and) という論理ゲートだけが予め用意されているので、 Nand を使って他の論理ゲートを実装していく。 実行効率についてはあまり考えずに、最初に浮かんだロジックをとりあえず実装して進める方針でやっていく。

以降は僕が実装したコードが出てくるので、ネタバレされたくない人は読まない方がよいです

Not

与えられた入力値を反転して出力すればいい。

Nandしか使えないので以下のような実装になった。

Nand(a=in, b=true, out=out);

PHPだとこんな感じになる

<?php
function not(bool $in): bool
{
    return nand($in, true);
}

And

入力値が2つとも True だったら True を出力し、それ以外であれば False を出力すればいい。

そもそも Nand!And なので、さらに否定すれば !!And となって And になるじゃんと思ったので以下のような実装になった。

Nand(a=a, b=b, out=nand);
Not(in=nand, out=out);

PHPだとこう

<?php
function and(bool $a, bool $b): bool
{
    return not(nand($a, $b));
}

Or

2つの入力値がどちらも False である場合に False を出力し、それ以外の場合は True を出力する。

Nand は 2つの入力値が True である場合のみ True を出力し、それ以外の場合は False を出力するという Or の動作と似てる感じだったので、入力値をそれぞれ否定すればいいんじゃねということで以下のような実装になった

Not(in=a, out=notA);
Not(in=b, out=notB);
Nand(a=notA, b=notB, out=out);

Xor

2つの入力値がそれぞれ異なる値の場合に True を出力し、そうでない場合に False を出力する。

OrNand がそれぞれ True を出力すれば2つの入力値が異なる状態であると言えると思うので、以下のような実装になった

Nand(a=a, b=b, out=nand);
Or(a=a, b=b, out=or);
And(a=nand, b=or, out=out);

Multiplexor

a,b,selという3つの入力値を受け取り、selが False であれば a を selが True であれば b を出力すればOK。

こういった分岐はif文を使うことが前提な思考になっていたので、少し戸惑ってしまった。
あと変数名をどうすればいいかわからなさすぎる

b の値を出力する場合は sel と b を And 関数に通せばいいが a を出力する場合はそうもいかない。
が、sel を反転すれば a も b と同じ扱いが出来るのではという感じで以下の実装になった。

Not(in=sel, out=notSel);
And(a=a, b=notSel, out=a1);
And(a=b, b=sel, out=b1);
Or(a=a1, b=b1, out=out);

Demultiplexor

in,sel という2つの入力値をとり、a, b という2つの出力をする。 sel が False であれば a=in, b=0 を sel が True であれば a=0, b=in を出力すればOK。

先ほどの Multiplexor を使えば簡単そうだったのでそうした

Mux(a=in, b=false, sel=sel, out=a);
Mux(a=false, b=in, sel=sel, out=b);

多ビットAnd, Not, Or, Multiplexor / 複数入力 Or, Multiplexor, Demultiplexor

他にも課題のゲートはいくつかあったが、新しい考え方は特になかったのでスキップ

感想

ブール関数だけで Multiplexor みたいなゲートを実装するのはすごく新鮮で面白かったなー

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:もちろんテストされていないアプリケーションコードを把握できるというのは大きなメリットです。

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にテストコードのディレクトリが含まれている場合は、そのディレクトリのカバレッジを計測してもマシンリソースの無駄なので除外します。 複数ディレクトリを除外したい場合は -d pcov.exclude="~(foo|bar)~" のような書き方をします。

僕は実行時のオプションでディレクトリの指定をしていますが、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くらいの方がおいしそうな気がする!

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