からかい上手の(元)高木さん(12)

最近は、(元)高木さんよりも、ちーの愛らしさにやられている。自分の子どもがちょうど同じくらいなのもあって、完全に重ね合わせてしまってるな。横になってるときに上に、お腹の上に乗ったまま寝ている姿とかね。まぁ、うちの場合は大きいから、乗られたら重さで絶対起きてしまうけど。

緊急事態宣言で大きな公園は閉鎖されているため、ここのところ週末は引きこもってばかり。解除されて公園も開いたら、涼しくなってきたことだし、自転車の練習にでも連れていかないとな。なんてことを「なみ」の回を読みながら思った。ほんと、西片はいい父親やってる。見習わないといけないな。

聖剣伝説3 TRIALS of MANA

スーパーファミコンで遊んだ聖剣伝説3のリメイク、『聖剣伝説3 TRIALS of MANA』を Switch でプレイし、全クリアした。主要3ルートだけでなく、追加シナリオの7章まで。シナリオと音楽の懐かしさ、一新されたグラフィックの新しさ、どちらも味わえてなかなか良かった。

リメイク版では、アンジェラとケヴィンが強すぎるな。エインシャントはチートだ。ホークアイの忍術もかなり使えた。デュランはアタッカー兼回復役として便利だった。雑魚戦はケヴィンの必殺技で瞬殺だし、ボス戦はエインシャント連発で楽勝。

強くてニューゲームのおかげで周回が楽だし、2周目からは経験値3倍のアビリティ使えるからレベルがガンガン上がっていく。普通にプレイしてても、3周目が終わるころには6人全員レベル99に到達する。

追加要素のサボテン君は全員見つけた。戦闘開始時SP200とペイバックを組み合わせたら、必殺技連発できて雑魚戦は瞬殺になった。経験値がたまに3倍になる特典と、常時3倍のアビリティ組み合わせたら、すごいペースでレベルが上がっていったな。

シナリオは、まぁ全年齢向けの昔の王道。分かりやすさ大事。ただ、デュランの旅立つ理由がクラスチェンジだったり、7章でクラス4がセリフとして出てくるのには違和感あったけど。擦れた大人になってしまったものよ。

スーパーファミコン版の時は、1つもルートをクリアせずに売った気がする。デュラン主人公で、竜帝直前でやめてしまった。それもあって、ストーリーは普通に楽しめた。良いリメイク。

聖剣伝説2のリメイクも遊びたいけど、あっちはSwitch版出てないのか。残念。聖剣伝説2も夢中になって遊んだ記憶があるので、いつかリメイク版をプレイしてみたい。PS5を買ったらいけるか?

からかい上手の高木さん(16)

高木さん16巻は調理実習回。高木さんが料理できるのは予想通り。高木さんが作った味噌汁を西片くんが毎日飲みたいとか言って、気付かないうちに反撃するのを期待したけど、間接キスでドキドキする止まりかぁ。オマケの方で娘のちーが反撃を受けたは予想外。

高木さんと西片くんで交換日記をはじめることになったのは、今後のための仕込みだろうな。交換日記に書いた内容でからかう回が何度かあるとみた。ていうか、交換日記って完全に恋人がやるやつじゃん。早く付き合ってしまえ。

CustomScriptExtension の commandToExecute で複数のコマンドを実行したメモ

CustomScriptExtension を使ってタイムゾーンを変更しても、既に実行中の Windows サービスには反映されなかった。反映するには Windows サービスの再起動が必要とはね。

commandToExec で powershell.exe を使い、-Command に複数コマンドを指定するハックで解決できた。PowerShell なら Restart-Service コマンドレットが使えるので、Windows サービスの再起動も簡単。

resource "azurerm_windows_virtual_machine_scale_set" "example" {
  # ...
}

resource "azurerm_virtual_machine_scale_set_extension" "custom_script" {
  name                         = "customscript-example"
  virtual_machine_scale_set_id = azurerm_windows_virtual_machine_scale_set.example.id
  publisher                    = "Microsoft.Compute"
  type                         = "CustomScriptExtension"
  type_handler_version         = "1.10"
  settings = jsonencode({
    "commandToExecute" = "powershell.exe -Command \"tzutil /s 'Tokyo Standard Time'; Restart-Service -Name Example\""
  })
}

Terraform で仮想マシンスケールセットのインスタンスのタイムゾーンを変更する方法

仮想マシンスケールセットのインスタンスタイムゾーンを日本時間に変更したいのに、仮想マシンスケールセットで動かすためのイメージを作るとき Sysprep で一般化したら、タイムゾーンUTC になってしまう。

応答ファイルでタイムゾーンを設定できたはず。カスタム応答ファイルを作ればいけるかと思いきや、ドキュメントによると、Azure はカスタム応答ファイルをサポートしていないときた。困った。

起動時に任意のスクリプトを実行するしかない。フックポイントがあるか調べたところ、CustomScript 拡張の存在を知った。 Terraform は仮想マシンスケールセットの拡張もサポートしている。

resource "azurerm_windows_virtual_machine_scale_set" "example" {
  # ...
}

resource "azurerm_virtual_machine_scale_set_extension" "custom_script" {
  name                         = "customscript-example"
  virtual_machine_scale_set_id = azurerm_windows_virtual_machine_scale_set.example.id
  publisher                    = "Microsoft.Compute"
  type                         = "CustomScriptExtension"
  type_handler_version         = "1.10"
  settings = jsonencode({
    "commandToExecute" = "tzutil /s \"Tokyo Standard Time\""
  })
}

こいつでタイムゾーンを変更できた。めでたしめでたし。

ASP.NET Core MVC で軽量 DDD

1人でフロントエンドとバックエンドの両方を開発していたら、DDD と軽量 DDD の区別が付かないような状況になってきた。個人的には軽量 DDD 上等。ただ、アーキテクチャに関して言えば、クリーンアーキテクチャはやり過ぎ感あるので、シンプルなレイヤーアーキテクチャを好んで採用している。

実践 DDD で紹介されているようなレイヤーアーキテクチャだと、アプリケーション層にあたるのがアプリケーションサービスで、プレゼンテーション層の Controller から呼び出すことになる。このアプリケーションサービス、責任多くなりがち。仮に1メソッドが1ユースケースだとしても、アプリケーションサービスにユースケースを詰め込む形になって、自分の中でしっくりこなかった。

そこで試行錯誤してたどり着いたのが、ユースケースをクラスとして切り出すやり方。1 ユースケース 1 クラス 1 メソッド 。これも、単一責任の原則と言えなくもない、かも。

public class RegisterProductUseCase
{
    public async ValueTask<RegisterProductResult> ExecuteAsync(
        RegisterProductCommand command)
    {
        // いろいろやるけど紙面の都合で省略
 
        return new RegisterProductResult.Success
        {
            Product = product, // いろいろやって登録できた製品をセット
        };
    }
}

public abstract class RegisterProductResult
{
    private RegisterProductResult() { }

    public sealed class Success : RegisterProductResult
    {
        public Product Product { get; init; }
    }

    public sealed class Error : RegisterProductResult
    {
        // 紙面の都合で省略
    }
}

ASP.NET Core MVC なら、DI コンテナに登録したユースケースを、FromServices で引数として受け取ることができる。コンストラクタインジェクションだと、コンストラクタの引数が増えがちだったけど、必要としているメソッドの引数で受け取ればスッキリ。

[Route("/products")]
[ApiController]
[Authorize]
public class ProductsController : ControllerBase
{
    [HttpPost]
    public async Task<ActionResult<Product>> RegisterProduct(
        [FromBody] ProductInputModel model,
        [FromServices] RegisterProductUseCase useCase)
    {
        var result = await useCase.ExecuteAsync(new RegisterProductCommand
        {
            // init でいろいろ詰める
        });

        return result switch
        {
            RegisterProductResult.Success success => success.Product;
            _ => BadRequest(ModelState); // 紙面の都合で手抜き
        };
    }
}

ASP.NET Core MVC を使って、ちゃんとした Web API を実装するとき、最近はこのやり方に落ち着いた。戻り値用の型を定義するのだけはいつも面倒で、TypeScript の Union 型が C# にも欲しいと、しょっちゅう思う。

アオアシ(25)

阿久津からアシトへの教えが、どうやって相手をハメてボールを奪取するかではなく、いかにボールを取られないことだったとはね。あと、敵ではなく味方のスカウティングも。

その教えの甲斐あって、アシトが司令塔として開花しそうな予感。そういえば、エスペリオンユースには、ゲームメイクしそうな選手がアシトの他にいなさそうだ。桐木はゴールに直結するラストパス送るタイプだし。近いのは大友だけど、どちらかというとリンクマン。

フィジカルや技術に劣るアシトが、ゲームメイクを武器に司令塔としてユース日本代表クラスまでのし上がっていけるのか。北野と役割かぶりそう。ライバルになるんかな。そうなったらアツイ。

あとアシトの兄・瞬が主人公の公式スピンオフは、徳島のユースに入る物語っぽい。作者が同じだから安心して読めそう。買おうか迷うな。