tech.guitarrapc.cóm

Technical updates

Pulumi で Stack解析中の例外でリソースが全て消えてしまうのを防ぐ

Pulumi は Stack の解析を行って、現在のステートとの差分でどのような処理をするか preview / up で表示します。 このため、Stack の解析中 (=コードをビルドして実行してStack生成中) に例外が生じたときにどのようにハンドルされるかは重要です。

今回は ユーザー側の誤った記述で、Stack解析に例外が起こっても処理が止まらず実行されたのをメモしておきます。

目次

tl;dr;

  • sdk/dotnet を利用する場合、Program.Main の返り値の型は int または Task<int> にしましょう
  • Top-level statement なら return を忘れずに、return await Deployment.RunAsync<MyStack>(); としましょう

どういう問題なのか

C# でPulumi を記述する場合、多くの場合は Stack を継承した自分の定義を用いるでしょう。 pulumi previewpulumi apply でStack を実行中に例外が発生した場合は、pulumi cli はそれを検知して実行を止めなくてはいけません。 pulumiは 例外を検知すると、「何もStackの内容を実行せず」例外をターミナルに表示して終了します。

しかしProgram.Mainメソッド の返り値の型を int あるいは Task<int> にしていないと、例外が起こっても pulumi cli は実行を継続しようとします。 この状態で例外が起こると、「例外以降のコードで記述されたリソースに削除マーカーを付与」して差分+例外をターミナルに表示して終了します。

// bad
public static async Task Main(string[] args)
{
    await Deployment.RunAsync<MyStack>();
}

// bad (Top-Level statement)
await Deployment.RunAsync<MyStack>();

Issue が作られておりそちらを見ると詳しくわかります。

github.com

対処方法は前述のとおり、Mainメソッドの返り値を intTask<int> にしましょう。

// ok
public static async Task<int> Main(string[] args)
{
    return await Deployment.RunAsync<MyStack>();
}

// ok (Expression-bodied Method)
public static async Task<int> Main(string[] args) => await Deployment.RunAsync<MyStack>();

// ok (Top-Level statement)
await Deployment.RunAsync<MyStack>();

何がおこったのか

Pulumi は言語のビルドは pulumi cli と切り離されているので、何気に .NET 6 でもビルド、実行できたりします。 その際にうかつにも、await Deployment.RunAsync<MyStack>(); と return を忘れて書いてしまったために、作成してあったリソースの多くが消えるという目にあったのでした。

// missing return!!
await Deployment.RunAsync<MyStack>();

Pulumi は GitHub Aapp あるいは GitHub Actions で PR で差分を表示できるのですが、GitHub Actions でコメントを書くのを使っていたために、差分が埋もれてしまい気づけなかったという顛末です。

対処は return をつけるだけです。 誰かの役に立つと幸いです。

Pulumi に期待すること

例外起こったら Environment.ExitCode = -1 など適切な終了コードをセットしてほしいです。 現在はそういったことをしていないのを、終了コードを Main メソッドで示さないと死ぬので基盤で対処してほしい...。

github.com

2021年を振り返って

毎年やっている昨年の振り返りをしてみます。2020年忘れてました。

2019年はこれ。

tech.guitarrapc.com

総合

2021年は、2020年にやったことをさらに深めていく年でした。 2019年からやっていることを深く広くしていくことが求められており、相変わらず毎日新しいことを学んでいます。クライアントにフルコミットが必要で、この自社の時間を設けるのが難しくて頭が痛い問題が解消しませんでした。

サービス基盤を全面的にみているのですが、基盤を安定させつつ、改善したり抜本的な変更をしていくことを継続的に行っています。省力で行うため2019年から IaC で100%管理を続けており、かなり有効なのでおすすめです。Kubernetes + IaC じゃないと手が足りなかったので選択は正解なのですが、相談できる仲間が足りないと感じていて2022年はかなり頭を痛めそうです。

2021年もわからないことへの挑戦の連続でしたが、教わったり助けてもらいつつ分からないことを1つずつ潰せもしました。来年以降の自分に投げつけた課題もありますが、今年一年みても、寝かせると問題が問題でなくなったり、問題への解決方法を見つけたりするので、優先順位をつけて寝かせるのは大事。

経営

2021年は、あとはリリースというところまで進めたプロダクトをリリースしない決定をしており、なかなかリリースできないというのを痛感しています。 自社よりも他から請け負っている仕事に力が使われているのは、2020年より強くなっており反省しかない。

2022年は2021年の反省を生かさないといけない年になります。

プログラミング

C#、Golang、TypeScript がメインです。

CSharp

2021年、C# でインフラからサーバー、クライアントまで完結できるかと思って取り込んでいたのですができるものですね。 インフラは Pulumi や aws-cdk を使うのですが、おおむね terraform でできることは Pulumi でカバーできます。

C# 10 が出て、C# はかなり手触りが良くなりました。 Minimal API と File scope namespace 、Implicit Global Namespace で本当に書くのが楽になりました。

IaC

Terraform と Pulumi をメインに使い、Bicep も使っています。 Azure で IaCをちゃんとやろうと思ったら、残念ながら Bicep は選んではいけないという学びが悲しかったです。

Pulumi は Pulumi Native が出たことで、Upstream である Terraform の対応が入らないと Pulumi の対応が入らないという悪循環が解消されつつあります。とはいえ Pulumi Native は Beta なだけあって Beta な品質で、特にステートとリソースの協調がまだまだ足りない感じです。(Tag が順不同で実行ごとに変更かかる、変更が安定して適用されないなどプロダクション品質ではない)

Terraform は 1.1 がかなりいい感じで、ようやく state mv が改善されました。このままよくなってほしいけど、Pulumi の State move はクソなのであっち方向にはいってほしくないところ。

dev.classmethod.jp

Terraform の CI/CD は、さんざん Terraform Cloud の VCS 連携を使っていましたが、API ベースでの連動に切り替えました。変なことできないという意味ではVCS連携がいいのですが、どうしても GitHub PR との連動が弱いので、バランスを見ると API ベースがいいですね。 とくに tfcmtgithub-comment の組み合わせはいい感じなので、おすすめできます。

Pulumi の CI/CD は GitHub Actions の v3 が出たのですが、安定して微妙な使い勝手です。Dockerベースの頃より格段にいいのですが、tfcmt のような楽な使い勝手じゃないのでなんとも微妙。

Kubernetes

Kubernetes と YAML の地獄、どうしようもないのだろうかと真剣に悩んでいます。 Kustomize や helm という問題ではなく、YAML を書くのがしんどい、とはいえ DSL 的に他から出すのもブラックボックスで嫌で詰んでる。

記事

17本、少な。 あんまり言語的なのを書かなかったのですが、社内やお手伝い先でさんざん書いていてちょっとブログに起こすのがしんどかったりします。

書くことはあるけど、またこっちにも書くのかとなっているのがよくないので反省です。

ライフスタイル

コロナ大変です。 2021年10月から少し収まったので久々に外出しましたが、好きなところに行くのは楽しいものです。

家の中は、吊り収納にはまっています。水回りは徹底的に浮かしているので、掃除がほぼ不要になって最高です。

スタンディングデスクを使ったことでメリハリも効いてきたので、2022年はよりよく頑張っていきたいところ。

2022年は?

クライアントとの協業は年々強くなっています。期待に応えていきたいところ。 そして自社のリリースも。

個人的にはC# + Kubernetes がどうなるか 2022年はカギになりそうです。

dotnet format を CI で行って継続的にコードフォーマットしていく

この記事は Qiita C# Advent Calendar 2021 7日目の記事です。

Visual Studio や Rider での コードフォーマットは個人で使うにとても良く、開発上は必須といえます。 しかしチーム開発でコードフォーマットをいい感じに標準化させたい、労力かけずにフォーマット修正をかけたいと思ったときには CLI で実行できてほしいものです。

dotnet には長らく標準的なコードフォーマッタ用のCLI がありませんでしたが、.NET 6 SDK からコードフォーマッタ dotnet format が標準組み込みとなりました。

今回は C#で開発するにあたり、CI でCLIを実行してC# のコードフォーマットを自動修正する方法を紹介します。

普段からやっていると開発上でフォーマッタで困らなくなるので、塵も積もれば的な良さを感じる人がいれば幸いです。

tl;dr;

  • CI を使ってコードフォーマットをかけて変更をPR、レビューを通して自分たちのルールを見直したり、変更を取り込むという一連のフローができるようになります
  • GitHub Actions で例を示しますが、ほかのCI でも同様に実施ができます
  • コードフォーマットの対象 csproj やcsファイルを絞れるので、Unity など指定プロジェクトを除外することも可能です
  • 週一程度の緩い利用からはじめて、ストレスにならない程度の運用から始めるといいでしょう

実行例

まずはGitHub Actionsを実行して作られたPRから見てください。

github.com

dotnet format で自動でPR を作る例

PR の Files の変更一覧

この記事で紹介するGitHub Actionsを使うと、dotnet format された結果がPRで上がってきます。 PR は StatsFilesTargetProjects を示しています。ひと月あまり運用していて、ここが足りない、みたい、というフィードバックを受けてこのような形になりました。

  • Stats: パスごとの変更統計
  • Files: dotnet format がかかったファイル一覧 (場合によってファイル数が膨大になるので閉じています)
  • Target Projects: 対象の csproj 一覧

GitHub Actions のワークフロー全体像

先ほどのPR を作る GitHub Actions を示します。 このGitHub Actions は src/dotnet にある sln に基づいて、C# プロジェクトを週一/手動 でコードフォーマットします。

gist.github.com

プロジェクトが見たい場合は、元のリポジトリをどうぞ。

github.com

dotnet format のポイントは3つです。

  • dotnet format を使うには、.NET SDK 6 を setup-dotnet action でインストールします
  • dotnet format は sln や slnf に対して実行するのがおすすめ。個別の .cs や csproj でも実行はできますが制御しやすいでしょう
  • --exclude を使って、コードフォーマットの除外ファイルやcsprojを指定できます。複数除外もできます

GitHub Actions の中身を軽く説明します。

  • 24行目: sln が含んでいる csproj を一覧で取得しています
  • 34行目: PR駆動時などに、dotnet format の問題をGitHub 上で示します
  • 38行目: ここで dotnet format をかけています
  • 42行目~: 変更があったか、変更の統計などを取得しています
  • 70行目: dotnet format で変更があった時だけ PR を作っています

dotnet format を使う基本

ドキュメント

.NET 6 の dotnet format は、Microsoft Docs で紹介されているので、まずは見てみるといいでしょう。オプションも一通り説明があります。

docs.microsoft.com

リポジトリを見ると使い方がすべて乗っています、おすすめ。

github.com

サブコマンドが3つありますが、気にせず dotnet format するのがおすすめです。何も考えず dotnet format をかけられる環境を維持しましょう。

  • dotnet format whitespace: fixes whitespace
  • dotnet format style: runs code style analyzers
  • dotnet format analyzers: runs third party analyzers

.editorconfig を用意する

dotnet format は .editorconfig をフォーマットルールにするので、まずこれを用意しましょう。

.editorconfig を sln と同じ階層に置いて、C# のフォーマットルールを .editorconfig に定義すれば準備完了です。(リポジトリルートに配置しても動作しますが把握が難しくなるので避けています)

例としたリポジトリで使っている .editorconfig は Roslynチームのをベースにしています。チームごとにルールがあると思うので参考程度に。

https://github.com/guitarrapc/githubactions-lab/blob/main/src/dotnet/.editorconfiggithub.com

.editorconfig 定義すると dotnet format だけじゃなく Visual Studio でも同じフォーマットルールが適用されます。dotnet format を使わなくても、チーム開発でコーディングルールを持っているところでは .ediitorconfig を活用するのが幸せです。Rider も editorconfig をサポートしています、VS Code は EditorConfig for VS Code を使いましょう。

editorconfig を書いてて悩むであろうものは severity だと思います。デフォルトでは severity: warning なルールは dotnet format 実行時に自動で修正されます。自動修正されてほしい、Visual Studio でも守ってほしいものは warning をベースにしていくといいでしょう。過激派は error もやるかもです。あるいは、dotnet format 実行時に --severity でレベルを指定できます。

OSS 開発で時々見かける、.cs ファイルごとにヘッダにライセンスを入れるとかも .editorconfigfile_header_template を定義すれば dotnet format で一発で適用できます。こんなの人のやることじゃないのでうれしいことが多いでしょう。

.NET 5 での dotnet format

.NET 5 でdotnet formatを使うには、dotnet tools を使うことになります。

www.nuget.org

.NET 6 で標準提供するにあたりコマンド体系が変わったので、この記事の GitHub Actions はそのまま使うことはできません。

.NET 5 時代のは何人か紹介されているので見るといいのではないでしょうか。

blog.shibayan.jp

www.meziantou.net

.NET 6 にするまでの過渡期にはほしいところもあるでしょう。

OSSライセンスを正しく理解するための本 を読んだ

OSSライセンス はむずかしい、のと同時にどんどん変わっていっているので学び続けないといけないというのがあります。

自分自身がOSSライブラリを公開しているので、ライセンスは何をつかうか、なぜというのをアップデートしていく必要があります。 一方で、仕事も同様かそれ以上に必要な情報を、誤解なく伝えられるようにありたいとも思います。(難しい)

ということで、OSSライセンスを正しく理解するための本 が気になったのでKindle版を購入して読みました。

https://www.amazon.co.jp/dp/B09JS4BSCHwww.amazon.co.jp

あんまり本のレビューはしないのですが、たまには書きます。そして本を読んで改めて、自分のライブラリは今後も MIT をベースにすると思います。

tl;dr;

OSSライセンス、これからもしっかり管理していこうという気持ちになったので、本の目標は達成できてそうです。

どう読み進めたのか

この本はコードが出てこない一方、自分の考えをフラットにしつつまとめる必要があるので、Notion を使って読み進めつつメモを取る形式で進めました。

Kindle で読んでたのですが、文章をカーソル選択もマークもできないのでこれは厳しい。電子本なのになにもできない悲しさ。語句の検索もできないのはつらいですね。(ことさら Notion にメモを書く必要があった)

大体6時間ぐらいかかったので、文量に対して時間かけて考えながら読んだようです。

気づき

OSSライセンスが各国の著作権法に根差しているというのは、そういえばと思いつつおぼろげだったことでした。(著作権といいつつどこの? というスタートラインが曖昧だったといえる)

OSSライブラリを「使用する」と「利用する」を基点として、明確に言語化されて例が示されているのは整理されます。(例えば、クラインアントとしてのバイナリ提供は? サーバーとしての提供は? 社内向けサービスは? デバッグで使うツールは? 負荷試験で使うツールは? などのよくあるものも含めて) よく考えてみても、利用と使用を明確に区別しているのは、説明するにあたって大事だけど意識していなかった。意識しなくても大きく解釈ずれることがないけど、伝えやすいと思います。

AGPLに関して著作権法上利用といえるか疑問(P113)、という著者の意見が素直に書かれていて、実際これってどうなんですかね? 私も疑問です。

日本における利用、使用の裏付けは、著作権審議会マルチメディア小委員会 ワーキング・グループ中間まとめ (平成10年2月 文化庁) に依るんですね。これはOSSライセンスで調べていても、たびたび出てくる出典ですが、ほかに出てこないのはそんなもの? もう少し裏付けないのかしらと思わなくもない。平成10年って。

www.cric.or.jp

分類がいわゆる「コピーレフト型、準コピーレフト型、非コピーレフト型」ではなく「BSDタイプ、GPLタイプ、LGPLタイプ、MPLタイプ」になっているのはなるほどでした。言ってることに大きな違いはないんだけど、これもわかりにくいと思う部分があり微妙ですね。 permissive かどうかに焦点を当てた視線も同じ本で触れられているといいんじゃないかなぁと思いつつ、発散して難しそう。 分類いろいろあるけど、個人的には Public Domain などの著作権放棄に触れた本が読みたい気持ちがわきました。

リバースエンジニアリングに関して、利用規約として改変の目的のためのリバースエンジニアリングは許可しつつ、機能分析のためのリバースエンジニアリングは禁止できるというのは新鮮でした。目的別に指定するという発想がなかった。

ライセンス管理の例として、ライセンス以外にライセンスタイプを書くことで対処しやすくするというのは良いと思いました。このライセンスだから XXXではなく、ライセンスのタイプだから XXX とするのは運用しやすい。

バージョンによってライセンスが変わるは、ここ最近もちょいちょいあるので結構難しいですね。アップデートしたらライセンス変わりますからね。調べないと気づけないのはまぁいいとして、変わったら強制的に気づく仕組みが欲しい。こういうのは人間のやることじゃないので仕組みで何とかしたいところです。Dependabot も脆弱性に応じて更新できてもライセンス変更をあれで気づくのは無理だしなぁ。ふと思ったけど、licensed 使ってないんですがどうなんでしょう。

github.com

気になったこと

フラットな立場1で書かれた本ではないと感じました。それは自由なのでよいのですが、フラットな文章が読みたいと思った時には手に取りにくい本です。

著者の主張が強く、不満に思っていることを本の中で文面にちょいちょい出されているので、うっと敬遠する気持ちが増します。主語が大きく、強い言い回しが多いので、軽く読みすすめようと思って結果疲れました。私はこういうの苦手なので、人にすすめることは難しいです。

静的リンクと動的リンクによる違いに触れてないので、ちょっとこれだけだと片手落ちな感想というかあまりよくない気配。 コンパイルとしての例があるので、静的リンクとしてはいいのだけどリンクの違いに触れてないので、この本だけで察するのはできなさそうです。

一部の主張は、10行前と矛盾していることを言っているように思ったので気になります。

出典不明なケースが数例あったのと、出典を示しつつ和訳のみがあるものがあり、解釈あってるかの再考証がむずかしいと思いました。出典がURL抜きで不明なものはちょっと困ります。

時々例示が古く、今それを例にするのかと思い残念です。(プリンタドライバーの例とか)

併せて読みたい

IoT 時代におけるOSS の利用と法的諸問題Q&A 集

future-architect.github.io


  1. 個人の好みはおいて、あるいはどのOSSライセンスがいいなどといった信条から距離をおいた立場

東プレ REALFORCE R3HC12 にメインキーボードを変更した

Realforce R3 が発売されました。

これまで Realfoce が抱えていた不満がほぼすべて解消されたモデルに見えるので、メインキーボードに据えてみました。

前回の R2TLS-JP4 から約4年での新モデル、実際どうなのか見てみます。

tech.guitarrapc.com

tl;dr;

R2 を有線で使って満足しているなら、R3 を買う動機は薄いと思います。 ただ、Realforce を 無線で使いたいならオススメです。 Realforce ConnectによるAPCやキーマップ設定も使ってみるとよいものです。

よく比較に挙げられていたNIZ と比較して足りないものはほぼなくなったので、正しく進化した感触です。 価格が高いのがネックですが、キーボードは職業柄一番使う道具なので更新していきたいところです。

余談ですが、キースペーサー2mm を入れると、キーボード入力が気持ち浅くなる以上に、入力音が低減されてよかったです。

簡易まとめ

  • R3 はベゼルは太い
  • スコスコは強くなった。(違和感ある人もいそう)
  • 静音はR2 より気持ち劣ってるかもしれない
  • Bluetooth で使って、キータップで自動復旧させるなら モード4 一択
  • Bluetooth なのに 1.3 kg あるのは、Realforce はそういうものといえばそうだけどちょっとちぐはぐになっていくかもしれませんね
  • キースペーサー2mm と APC 1.5mm で、メンブレンタイプも試せるように矯正したりもできる

外見と特徴

ホームページから見てみましょう。

www.realforce.co.jp

特徴的なのが、上部のボタンとインジケーターランプです。

見た目は R2 から初代に戻っており、サイズとベゼルが残念です。

R2 に比べてベゼルが太く、角がの丸っこいため初代に近く感じます。

サイズを見てみましょう。

モデル サイズ
R2 142mm x 369mm x 30mm
R3 163mm × 379mm × 30mm

キーピッチ、キー入力の配置感覚はは変わらないので、単純にベゼルが増えた分だけ上下左右に長くなっています。

  • 横方向は、キーピッチの配置で合わせると左右に微妙に伸びただけで案外違いは分かりません
  • 上方向は、1cmあまりの差がはっきりわかります。ボタンとインジケータで増えたにしては大きかった

上 R2、下R3 で横合わせ

上 R3、下R2でキーピッチ合わせ

スペースはR2より少し短くなり、初代ぐらいになっています。

そのほか

R3 は R2 と違い、モデルによらずキー印刷はレーザー印刷です。

今回購入したのは、Bluetooth 5.0 & USB 有線のハイブリッド接続なので、USB C - USB A ケーブルがつけ外し可能になっています。(Realforce 側が Type-C)

Bluetooth は、バスパワーか単三電池x2 で動作します。

キープラーや替えのキートップは同梱されませんので注意です。 キートップは別売りでさまざまな色が売られるようなので、面白そうですね。黒 + 黄 などもよさそうです。

https://www.realforce.co.jp/products/R3_key-caps-set/www.realforce.co.jp

操作

電源ボタンが追加されました。1秒長押しするとつながります。

Fn キーと一緒に、キートップ側面に書かれたキーを押すと各種操作ができます。

よく使うものをあげてみると

  • Fn + P で、Bluetooth のペアリングができます
  • Fn + 1~4 で Bluetooth 接続先を4つキーボードが記録でき、 Fn + 5 でUSB 接続に切り替えることができます
  • Fn +F9 でバッテリー状態を確認できます
  • Fn +F11 で、Bluetooth のエコモードを切り替えられます

取説にも説明がありますが、側面を見るとすぐにわかるのは便利ですね。

Bluetooth 接続時の復旧

Bluetooth キーボードやマウスは、電池節約のために自動的に切れるのが一般的です。 R3 も例外にもれず、Bluetooth 接続時はエコモードが働きます。

エコモードは全部で4モードあり、デフォルトはモード 1です。

取説のエコモード

取説の時間放置後の復旧を試したのですが、モードごとの違いは次の通りです。

  1. 10分でキーボードがスリープ。キータップでは復帰せず、電源ボタン1秒長押しでキーボードの電源onが必要
  2. 10分でキーボードがスリープ。キータップでは復帰せず、電源ボタン1秒長押しでキーボードの電源onが必要
  3. 30分でキーボードがスリープ。キータップでは復帰せず、電源ボタン1秒長押しでキーボードの電源onが必要
  4. 30分でキーボードが切断。キータップで自動的に再接続して、2キー入力から使える

私は時間が経ってキーボードとPCがつながらくなっても、何かしらのキーをタップしたら復旧してほしいと考えています。 この要件にあるのは「エコモード4」だけでした。 1~3 の電源長押しが必須なのはちょっと受け入れがたいです。

気になるのが、4の切断でスリープとちがうということはスリープしないんですかね。 とりあえず単三電池で使っていますが、どうなるのか今後が気になります。(3か月も持てば十分ですが)

キータッチの違い

R2 と比べて、R3 は、スコスコ感が増したようです。 良くも悪くもスコスコ、好みはあるかもしれませんがすぐに慣れて R2 を忘れたので私にはその程度でした。

ただ、R2と同じ静音ですが、少しキーボードがうるさい気がします。

キースペーサーを2mm を試してみるので、静音やタッチ感覚がどうなるか楽しみです。

www.realforce.co.jp

Realforce Connect

Realforce のだめといわれた最大のゆえんは、お高いわりに調整がしょぼいことです。

R3 ではRealforce Connect をインストールして、USB でつなぐとAPCやキーマップの入れ替えが可能におなっています。

例えば、APCモデルならデフォルト2.2mm から「キーボード全部」や「キー個別」に浅くしたり深くしたりが可能なのはうれしいところです。

キーマップの入れ替えも、Windows レジストリや機能を使うことなくキーボードで完結できます。今回は、Caps lock を Ctrl にしました。

変更後のキーマップ。Caps Lock を L-Ctrl に切り替えている

面白いところでは、今のキーストロークの深さがわかる機能もあって、普段自分がどれぐらいの深さで入力しているのかがわかります。

Realforce Connectでキーストロークの深さが可視化される

惜しむらくは、USB接続していないと接続を検知してくれないことでしょう。 普段 Bluetooth 接続なので、気になったときにUSBにつなぐのは面倒ですね。

Windows の Japanese IME 設定

スペースの左右にある無変換、変換をそれぞれ IME-off / IME-on に割り当てています。これは、macOS は英字、日本語になっているので合わせているのですが、日本語キーボードで頻繁に日本語、英字の切り替えをするので便利です。

日本語 IME > キー & タッチ

キースペーサー2mm を入れてみる。

2021/11/9 2mm のキースペーサーをつけてみました。

キースペーサーをつける前

キースペーサーをつけた後

Realforce Connect で見ると、キーストロークはFull に近いようですが、APC 1.5mm にしてより軽くタイプできるようにもしてみました。

期待した効果ですが、装着前と比べて次の違いがあります。

  • キーストロークの深さが、気にするとわかる程度に浅くなった
  • キーボードのカタカタ音から高音が減ったことで静かになったように感じる

耳の位置あたりで録音したものを聞くと、普段の Realfoce R3 は結構うるさく感じますね。静音とはいえ、録音するとそういうものなのかもしれません。