著者アーカイブ 杉浦

著者:杉浦

NaNの比較

 NaNはNot a Numberの略であり、その名の通り数字でない値を表します。主に数字として解釈できないものを数字と解釈しようとしたときに現れます。web系の言語で出会うことは稀です。
 NaNは歴史的経緯なのか厳密に数学を取り扱っているからかなのかプログラミング領域から見ると少々直感的でない動作をすることが多いです。よくあるのがNaNの比較です。

const a == NaN
a == NaN // false
NaN == NaN // false

 NaNであること調べようとした時、NaNオブジェクトとイコールである、と式で書くとfalseが返ってきます。例はJavaScriptですが他言語でも同様です。これはNaNが数字で表せない値、転じて不明な値を表現しているためです。不明同士を比較しても結果は不明です。
 NaNであることを調べるためには特定の関数を使います。大体isNaNとかそんな感じの名前で用意されているのでそちらで調べます。

$nan = acos(8);

var_dump($nan); // float(NAN)
var_dump(is_nan($nan)); // bool(true)
著者:杉浦

【PhpStorm】Redis連携用プラグインRedisの紹介

 PhpStormは主にWeb開発を主眼としたIDEです。データベース回りとの連携は便利なのですが、Redisとの連携は組み込みでありませんでした。プラグインの追加が必要になりますが、一択に絞れるような選択肢はありませんでした。いくつか試して最もおすすめなのはRedisです。
Redis – Plugins | JetBrains
 Redis(プラグイン)の特に良い点は二点、一つは画像の様なデータベースのGUIと同じように扱える程よく簡素なGUIです。


 熟達いらずに何となく分からない場所を触って確かめるだけで機能の多くを把握できます。
 もう一つは無料という点です。PhpStormのRedisプラグインの競合相手の大手には有料であるIedisがあります。
Iedis – Plugins | JetBrains
 こちらはRedisの外(Json、XMLなど)へ出力、Redisサーバ自体の設定などが詳細にできます。この辺り、プラグイン自体をソフトウェアに扱うならIedisに軍配が上がります。一方でRedisサーバとの読み書き機能自体はRedis(プラグイン)とそう変わりません。自分はデバッグ回りが主な使い道なのでRedisサーバとの読み書きこそが主になるので、無料である点の方が重要でした。

著者:杉浦

【Vue.js】コンポーネントの持つ値をCSSに伝える

 Vue.jsで小さなコンポーネントを作っていると時折デザインの一部をコンポーネントを呼び出す側で自由に決定させたい時があります。この記事ではそのやり方を紹介します。
 コンポーネントの持つ値をCSSに伝えるために重要な機能はCSSにおける変数であるカスタムプロパティです。
 カスタムプロパティ (–*): CSS 変数 – CSS: カスケーディングスタイルシート | MDN
 CSS カスタムプロパティ (変数) の使用 – CSS: カスケーディングスタイルシート | MDN
 カスタムプロパティは次のように用います。カスタムプロパティの適用対象は定義したHTMLElementの子方向の要素全てです。

div.hoge-box {
    --hoge-box-width: 3em; /* --hogeで宣言 */
    width: var(--hoge-box-width); /* var(--変数名)で使用 */
}

div.hoge-box > div {
    width: calc(var(--hoge-box-width) / 6) /* calcでも使える */
}

html {
    --global--base-color: hsl(0, 0, 0); /* html, :root, bodyの様な広い範囲で指定するとグローバル的に使える */
}

 コンポーネントのルートエレメント上でコンポーネントの持つ値を用いてカスタムプロパティを定義することでCSSへ任意の値を与えます。これは例えば次のようにpropsで与えられた値をcomuputedでまとめ、まとめた値をルートエレメントであるdiv.check-boxのスタイルとして定義、定義した変数をCSS内で扱う、というやり方です。

<template>
  <div
    :style="styleVariables"
    class="check-box"
  >
    <div class="check"/>
  </div>
</template>
<script>
export default Vue.extend({
  props: {
    checkboxWidth: {
      type: String,
      default: '3em',
    },
  },
  computed: {
    /**
     * このコンポーネント中で用いるCSS変数をまとめる.
     * @return {object}
     */
    styleVariables() {
      return {
        '--checkbox-width': this.checkboxWidth,
      };
    },
  },
};
</script>
<style lang="scss" module>
  .check-box {
    --checkbox-width: 3em;// 事故防止のデフォルト値
    border: 2px solid #9e9e9e;
    border-radius: 2px;
    width: var(--checkbox-width);
    min-height: var(--checkbox-width);
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .check{
    position: relative;
    top: calc(var(--checkbox-width) / 6); // def=0.5em
    left: calc(var(--checkbox-width) / -20);// def=-0.15em
    transform: rotate(-45deg);
    transform-origin: left top;
    border-left: 2px solid #000;
    border-bottom: 2px solid #000;
    width: calc(var(--checkbox-width) / 2.4 * 1.618); // def=2.0225em
    height: calc(var(--checkbox-width) / 2.4); // def=1.25em
  }
</style>

 上記コードの動作は次のデモの通りです。

 いたるところでサイズをemで指定していますが変数を介しているためデザインを崩さずデザインを容易に変更できます。変数はコンポーネントのプロップで決定しているため、コンポーネントを呼び出す側が安全にデザインを変えられます。この変数渡しのやり方に加えて、アニメーションや状態の定義と変化を用いることで自由に簡単に扱える最小単位のコンポーネントを作りやすくなります。
 余談ですが、カスタムプロパティを用いる際、CSS独立ファイルでは未定義の変数名を呼び出そうとするか、定義セレクタを多量にコピペすることになり辛くなります。SCSSの様な階層構造を定義できるCSS拡張言語を用いると安全に簡潔に記述できます。

// scssコード
div.hoge-box {
    --hoge-box-width: 3em; // --hogeで宣言
    width: var(--hoge-box-width); // var(--変数名)で使用

    div { // div.hoge-box divと同じ意味になる
        width: calc(var(--hoge-box-width) / 6) // calcでも使える
    }
}
著者:杉浦

【Laravel】6.0.4リリースとLaravel製APIテストの拡張

 Laravel6.0.4がリリースされました。
 Releases · laravel/framework
 機能の追加は次の通りです。

Added

  • Added TestResponse::assertJsonPath() method (#29957)
  • Added hasMacro \ getGlobalMacro \ hasGlobalMacro methods to Eloquent Builder (#30008)
  • Added Illuminate\Database\Eloquent\Relations\BelongsToMany::getPivotColumns() method (#30049)
  • Added ScheduledTaskFinished \ ScheduledTaskStarting events to signal when scheduled task runs (#29888)
  • Allowing adding command arguments and options with InputArgument \ InputOption objects (#29987)


 自分にとって特別な追加はTestResponse::assertJsonPath()です。これのおかげでAPIのミドルウェア込みテスト(疑似的なリクエストを投げて、ルーターとコントローラを通して、レスポンスを返してもらって、レスポンスをチェック)をより簡潔に必要な分だけ作れる様になりました。
 LaravelのTestCaseではAPI用にJSONレスポンス用のassertが用意されています。もともと用意されていたのは大規模にならざるを得ないメソッドや素朴すぎるメソッドです。例えば、assertExactJsonがあります。これは完全一致のJSONを期待するassertで次のように使います。

$this->getJson(route('api.post.show', [$post->id]))
	->assertExactJson([
	    'title' => 'My blog post',
	    'body' => 'Lorem ipsum ...',
	    'tags' => [],
	    'comments' => [
	        [
	            'body' => 'First!',
	            'user_id' => 42,
	            'user' => [
	                'id' => 42,
	                'username' => 'ecrmnn',
	            ],
	        ],
	        [
	            'body' => 'This is my comment',
	            'user_id' => 731,
	            'user' => [
	                'id' => 731,
	                'username' => 'ventrec',
	            ],
	        ],
	    ],
	]);

 これはこれで便利なのですが、細かい単位でテストし難いです。また、同じコントローラメソッドを繰り返しテストすると微妙な差分の期待するJSON定義が膨らみます。もっと言えば、何をテストしたいのかぱっと見分かりません。Laravel6.0.4で追加されたassertJsonPathはこれを解決します。次のコードの様に、JSONの特定のパスについてのみassertをすることで簡潔に必要な分だけ検査をできます。先述のassertExactJsonをassertJsonPathに書き直すと次のようになります。

$this->getJson(route('api.post.show', [$post->id]))
    ->assertJsonPath('tags', [])
    ->assertJsonPath('comments.0.user.username', 'ecrmnn')
    ->assertJsonPath('comments.*.body', [
        'First!',
        'This is my comment',
    ]);

 ちなみにJSONレスポンスを期待する疑似リクエストを投げる時のコードは次のようになります。get, postのみならずput等HTTP2.0で定義されるメソッドにも対応しています。

class HogeControllerTest extends TestCase
{
    public function HogeTest(){
        $this->getJson(route('hoge'));
        $this->postJson(route('hoge'), ['id' => 0, 'password' => '']);
        $this->deleteJson(route('hoge'), ['id' => 0]);
    }
}
著者:杉浦

【Laravel】public static function hogehoge()とpublic function scopeHogehoge()の使い分け

 LaravelのEloquentにはクエリビルダでチェーンを組むための命名規則に従ったメソッド作成方法があります。scopeHogehoge()とするとModel::hogehoge()とするとクエリビルダが走ります。この状態のまま次のようにチェーンを組めるのが利点です。

User::hogehoge()->orderBy('fuga')->limit(30);

 検索などでクエリの一部を使いまわしたい時などとても助かります。助かるのですが、この手法はモデルにも継承元であるEloquentにも記述されていないメソッドを呼び出しており、IDEのヘルパが効かず、警告も出力されます。次のようにコメントを記述することで対策できますが、コメントを経由して改めてscopeHogehoge()を検索する必要があります。

/**
 * @method static Builder|User newModelQuery()
 * @method static Builder|User newQuery()
 * @method static Builder|User query()
 * @mixin Eloquent
 *
 * @method static Builder|User Hogehoge()
 */
class User extends Model
{
    public function scopeHogehoge($query)
    {
        return $query->where('なんやかんや');
    }
}

 クエリが増えるにつれどんどんコメント→実際の記述と追うのが面倒になりだします。自分の知る使えそうな小技は二つです。一つはコメントの長大化の弊害がありますが次のようにコメントすることです。@seeはによってIDEはジャンプができる様になります。PhpStormならCtrl+Bです。

/**
 * @method static Builder|User newModelQuery()
 * @method static Builder|User newQuery()
 * @method static Builder|User query()
 * @mixin Eloquent
 *
 * @method static Builder|User Hogehoge()
 * @see   \App\Models\Eloquents\User::scopeHogehoge
 */
class User extends Model
{
    public function scopeHogehoge($query)
    {
        return $query->where('なんやかんや');
    }
}

 もう一つはstaticなクエリビルドメソッドを作ることです。Model::からクエリビルドする時はEloquentクラス中の次のメソッドが呼ばれています。これを使うことで任意のクエリをグローバルスコープ等欠けさせることなく使えます。staticなのでクエリビルド用の別クラスを用意することも簡単です。

class Eloquent
{
...
    /**
     * Begin querying the model.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public static function query()
    {
        return (new static)->newQuery();
    }
    /**
     * Get a new query builder for the model's table.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function newQuery()
    {
        return $this->registerGlobalScopes($this->newQueryWithoutScopes());
    }
...
}

 次が例です。再利用するあてのないメソッドならあと腐れなくstaticにできます。またこのstaticメソッドでビルダーを返せば、後にクエリビルド用のメソッドチェーンを続けることもできます。

public static function hogehoge($name)
{
    return self::query()->whereName($name)->first();
}
著者:杉浦

【Git】package.json上でコマンドとGitを連携させるためのhusky, lint-staged

 husky – npm
 lint-staged – npm
 huskyはGitのフックのほぼ全てをpackage.json上で定義できるパッケージです。フックできない部分はいずれもGitリポジトリを管理するサーバサイド用フックのみです。huskyのインストールと使い方は次の引用の通りです。

Install

npm install husky --save-dev
// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "npm test",
      "pre-push": "npm test",
      "...": "..."
    }
  }
}

typicode/husky: 🐶 Git hooks made easy#multiple-commands

 複数コマンドを実行するときはtypicode/husky: 🐶 Git hooks made easy#multiple-commandsにある様に、コマンド間を&&で区切るcmd && cmdかhusky個別の設定ファイルを用意します。すべてをpackage.jsonで完結させつつも、コマンドを&&で無理やり繋げない小技にnpm-run-all – npmを用いるやり方があります。次の様にあらかじめ小さいスクリプトを定義してnpm-run-allを介してまとめてhuskyで呼び出します。

{
    "scripts": {
        "php-cs-fix": "./vendor/bin/php-cs-fixer fix -vvv",
        "eslint": "./node_modules/.bin/eslint resources/**/*.{ts,js,vue} --fix",
        "php-unit-test": "php ./vendor/phpunit/phpunit/phpunit --configuration phpunit.xml tests/Unit --teamcity",
        "pre-commit": "npm-run-all eslint php-cs-fix",
        "pre-push": "npm-run-all php-unit-test"
    },
    "husky": {
        "hooks": {
            "pre-commit": "npm run pre-commit",
            "pre-push": "npm run pre-push"
        }
    }
}

 huskyだけでもコミット前のスクリプト起動漏れを防げて楽ですが、コミットのたびにフルでlintが走る上にlintで修正された分はコミット内容に含まれません。lint-stagedでこの問題を解決できます。
 lint-staged – npm
 lint-stagedはコミット用にステージングされたファイルの内、globで特定した対象のファイルについてのみ特定のコマンドを実行するパッケージです。対象ファイルはglob形式で指定します。大体*.{拡張子A,拡張子B}の様に指定するだけです。test絡みで通常のlintの対象にしたくない場合は!(*test).jsの様に!()を使います。!(*test).jsならばhogehoge.jsはlint, hogehoge.test.jsはnot lint。
 lint-staged実例として次のような設定をし、Hoge.jsとFoo.phpファイルをコミットしようとするとします。

{
    "lint-staged": {
        "*.{js,ts,vue}": [
            "eslint --fix",
            "git add"
        ],
        "*.php": [
            "php ./vendor/bin/php-cs-fixer fix -vvv --config .php_cs",
            "git add"
        ],
        "*.{json,css,scss}": [
            "prettier --write",
            "git add"
        ]
    }
}

 その様な場合、まず”*.{js,ts,vue}”の表現にマッチしたHoge.jsを引数として”eslint –fix Hoge.js”, “git add Hoge.js”が実行されます。Hoge.jsがESLintの自動修正によって修正され、Hoge.js全体がコミット対象になるわけです。これでコミット前に自動でlintが走り、lintの修正結果もコミット内に反映されます。Foo.phpでもphp-cs-fixerで同様にlintによる修正がかけられ、両方が終わった後に改めてコミットされます。
 husky, lint-staged, 各Linterを導入してpackage.jsonに次の様な記述を加えるとコミットのたびにLintが便利な形で走ってくれます。

{
    "husky": {
        "hooks": {
            "pre-commit": "lint-staged"
        }
    },
    "lint-staged": {
        "*.{js,ts,vue}": [
            "eslint --fix",
            "git add"
        ],
        "*.php": [
            "php ./vendor/bin/php-cs-fixer fix -vvv --config .php_cs",
            "git add"
        ],
        "*.{json,css,scss}": [
            "prettier --write",
            "git add"
        ]
    }
}
著者:杉浦

オブジェクトのライフサイクルから見たモデルの分割

 プログラミングにおいてモデルを作る時は、大体何か一つのモノを表すモデルを作ります。何か一つというのが曲者でして、含意の広い一つのモノを対象にモデルを作るとコードが肥大することがあります(含意すべてを入れても小さい場合や共通処理から外れない場合があって、そういう時は問題が起きなかったり)。この分割の仕方にライフサイクルの観点から分割する方法があります。 モデルはある範囲のモノを抽象化して表現します。これを具象化してオブジェクトを作成する際、オブジェクトの操作を実行した後に保存する際にそれぞれ処理が入ります。ファイルシステムやデータベースに保存されている情報を表すモデルの場合は特にこれが顕著です。下図はEric Evans. エリック・エヴァンスのドメイン駆動設計 (Kindle の位置No.3058). 翔泳社. Kindle 版. からの引用図です。

 正直、図の完成度が高いです。モデルが肥大する兆候が見えたら図の矢印ごとに分割するだけでかなり整理できます。
 記事が短いので以下例の様なものを書きます。例ではDB(データベース)には既に値があり、保存はDBに行うと考えます。上図の再構成、格納、修正の部分を取り扱います。DBの一語だけであるモデルに関することを全てモデルの一クラスに記述すると破綻しそうなのが想像できます。少なくとも、再構成の際にDBへの問い合わせ方法(FROM table、PDOなど)が必要になり、柔軟な検索条件の取り扱いも高頻度で必要になります。格納の際にもDBで行えないバリデーション、複数の関係するデータについての同期が必要になります。これらの上でモデル自体の振る舞いについても必要になります。分割が必要です。
 DBの例では問い合わせ、格納、振る舞いの三分割ができます。フレームワークが備えていることの多いORM(オブジェクト関係マッピング)においては大体、問い合わせが隠蔽されています。データベース定義とコード内容を分離させたい際にのみ生成に関する追記が必要になるでしょう。格納もDB命令部は隠蔽されがちで関係設定が定義されいれば勝手に同期してくれます。バリデーションのみが必須です。ルールが複雑化する場合、あるルール一つを表すモデルを作るのもいいでしょう。残ったのは振る舞いです。これはアクティブ状態で直に参照できない方が問題の部分であり、インスタンス化されたモデルの本質といっていい部分です。

著者:杉浦

【PHP】全く異なる複数クラスを疑似継承する黒魔術

 PHPの継承は常に単一です。これによって知るべき親クラスの情報を単純化してコードの複雑度を上げにくくしてあります。多段継承こそあれ複数経路は作れません。

class Hoge extends Foo // Foo一つを継承することはできる
class Fuga extends Foo,Bar // FooとBarを同時に継承するのはだめ

 やりかたはDI(Dependeny Injection)とマジックメソッドの応用です。

class Foo {
    public function echoFoo() {
        echo 'foo';
    }
    public function selfIntroduction() {
        echo "I'm foo.";
    }
}

class Bar {
    public function echoBar() {
        echo 'bar';
    }
    public function selfIntroduction() {
        echo "I'm bar.";
    }
}

class FooBar {
    public $foo;
    public $bar;
    
    public function __construct($foo, $bar)
    {
        // if コンストラクタでこけるのをいとわないか引数を気にしないなら:
        //     DIせず、ここで$this->foo = new Foo()の様に直接インスタンス化することもできる
        $this->foo = $foo;
        $this->bar = $bar;
    }

   public function __call($name, $arguments)
    {
        method_exists($this->foo, $name)
         ? $this->foo->$name($arguments)
         : $this->bar->$name($arguments);
    }
}

$f = new Foo();
$b = new Bar();
$fb = new FooBar($f, $b);
$fb->echoFoo();// foo
$fb->echoBar();// bar
$fb->selfIntroduction();// I'm foo.

 実行結果はコメントの通りになります。環境によってはセキュリティ問題でWARNINGが出ます。
 このようにするとFooBarインスタンスで未定義のメソッドが呼ばれたとき、DIしたfooのメソッドが存在するか確認し、fooにあればfooから実行、fooにもなければbarのメソッドを探し実行します。同様のやり方でstaticメソッド、プロパティも継承もどきができます。
 この方法を使えば簡単に全てのクラスの役割を持った神クラスを作れますが、もちろんそんな状態は作るべきでありません。複雑さに際限がなくなりコードを追うのも動作を理解するのも大変になります。

著者:杉浦

【Vue】Vuexことはじめ

Vuex は Vue.js アプリケーションのための 状態管理パターン + ライブラリです。
Vuex とは何か? | Vuex

 Vuexは上記の様にVue.jsで作成したプログラム中の状態管理を担うライブラリです。乱暴な言い方をするとVuexは管理しやすいグローバル変数を提供してくれます。Vuexのやることはコードと合わせてを見るとわかりやすいです。

// Vuexのストア(状態管理定義)の記述
export const HogeStore:Module<any, any> = {
    // 管理する状態。グローバル変数の本体的なモノ。
    // これを好き勝手弄らせないが、どこからでも参照できるようにする。
    state: { 
        foo: [],
        bar: false,
    },
    // 管理する状態を直接弄ることのできる関数群。ここにある記述以外ではstateを変更できない。
    // store等を介して、commit()関数で呼び出してのみ実行される。
    // 下記の様に思いっきり抽象化すると扱いやすい。
    mutations: {
        setFoo(state, newFoo){// state.fooを変更する
            state.foo = newFoo;
        }
    },
    // 具体的なcommitの内容を記述する。
    // コンポーネント中でstore.dispatch(アクション名)とやると直接commitするより安全安心。
    actions: {
        setFoo(context, newFoo){// state.fooを変更する.mutationsと名前がかぶってもOK
            context.commit('setFoo', newFoo);
        },
        pushFoo(context, newFoo){// state.fooに追記的な
            context.commit('setFoo', newFoo);
        },
        async resetFoo(context){// state.fooをAPI等のリポジトリから取得して改めてセット
            const newFoo = await FooRepository.get();
            context.commit('setFoo', newFoo);
        }
    }
}
// コンポーネント側の記述
// 参照の際には算術プロパティを利用すると便利
computed: {
    foo: {
      get() {
        return store.state.HogeStore.foo;
      },
      set(newFoo) {
        store.dispatch('setFoo', newFoo);
      },
    },
},
methods: {
    async reset() {
        await store.dispatch('resetFoo');// dispatch('アクション名')でactions中のメソッドを呼び出す
    }
}

 公式を読むともっと多彩なことができますが、とりあえず上記のだけでも十分に機能を発揮します。setterが厳格でgetterが自由なグローバル変数な印象を受けました。getterは追記できるため同じリソースを多角的に読みたい際も複雑さがそれほど増しません。
 Vuexを用いるタイミングですが、コンポーネント間のemitが長大になる時でしょう。例えば、あるコンポーネント群(メニューとか検索ボックス)はリソースを取得、あるコンポーネント群(表とかグラフとか)はリソースを表示、あるコンポーネント群(編集モーダルとか)はリソースを加工、とかやりだすと値の変更を4つ5つ越しのコンポーネントに伝播させる必要が出たり、その伝播のルートが3つ股4つ股になったりと煩雑になります。Vuex抜きにこれを整理しようとすると各コンポーネント群の重心であるメインコンポーネント(コンポーネントを呼び出すコンポーネント。App.vueとかPages/Fuga.vueとか)の中に処理が集中しだします。こうなるとメインコンポーネントのやっていることがまさしくVuexのやるべきことになります。
 Vuexはコンポーネント間の依存が直列や一方向の様な整然とした場合は不要ですが、そうでない時は値のやりとり最低限になりすっきりします。また純粋なTypeScriptで記述ができるため動作を明確にしやすいです。先述の例の様にVueアプリが複雑な場合、どこかしらでVuexの役割を既に担おうとしている部分があります。ソースコードが複雑化し、もうどうにもならない時はいっそ後付けでVuexを追加する良いです。

著者:杉浦

【Windows10】起動時に高頻度でブルースクリーンになる問題の対処法の一つ

 結論として、対処法の一つは高速スタートアップを切ることでした。切り方は以下の通りです。

アドレス:コントロール パネル\ハードウェアとサウンド\電源オプション\システム設定
UIを使った移動経路:コントロールパネル->ハードウェアとサウンド->電源オプション->電源ボタンの動作を選択する
移動した場所にある「高速スタートアップを有効にする(推奨)」のチェックを外す。
※チェックを外す前に「現在利用可能ではない設定を変更します」のメッセージをクリックする必要がある場合があります。


 これをするとPCが健康になる場合があります。勝手な想像ですが、高速スタートアップをするべきでないPCスペックであるにも関わらず高速スタートアップをしようとしていたのでしょう。
 以下、解決までの道筋です。
 今回起きていた問題は題にある通り、起動時に高頻度でブルースクリーンになる、というものでした。今回の問題の厄介な点はブルースクリーン時に表示されるエラーコードが多様だった点にありました。例えば、SYSTEM_THREAD_EXCEPTION_NOT_HANDLED、MEMORY_MANAGEMENT、BAD_POOL_CALLERです。このためエラーコードをググってピンポイントな解決を見つけることができませんでした。起きているエラーについて詳しく調べることでGoogle先生の提案する解決策を絞り込めます。エラーについて詳しく調べるにはWindowsのログを追うことが一つのやり方です。
 Windowsのログはコンピュータの管理のイベントビューアーから見ることができます。ここからエラー、警告、重大といった問題の起きそうなイベントのログを見ます。今回ならばとりあえず終了時の問題か、起動時の問題かの二択が想像でき、どちらの問題か調べようとしました。このログを見る限り、起動時に問題が発火、大炎上しています。

 これの中を読んでググってとしていくと起きていることがエラーコードのみよりもずっと深くわかります。今回は起点が常に高速スタートアップの失敗で、まさにそれが原因でした。(下図の様に高速スタートアップの失敗がいつも起きていた。そこから派生していくイベントのどこかしらで決定的な破綻が発生。)
 

 後は”高速スタートアップ”でググって予測で出てきた”高速スタートアップ 無効”で提案されたやり方を適用して処置完了です。
 処置後の経過をざっくり見るには信頼性モニター(コントロール パネル\システムとセキュリティ\セキュリティとメンテナンス\信頼性モニター)が便利です。以下の様に起きたイベントからPCの状態を評価、表示してくれます。処置後は回復に向かっており、一度も起動時のブルースクリーンは起きていません。