C# のメモリ安全性の改善

2026/05/22 1:54

C# のメモリ安全性の改善

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

C# 16 は、メモリ安全性の主要な転換をもたらしており、「unsafe」キーワードを暗黙的な許可から、開発者の明確な義務を定義する明示的でレビュー可能な契約へと変えました。この変更により、ポインタ型と安全性は厳密に分離され、ポインタ自体が自動的に unsafe アクセスを付与することはなくなり、明示的にデ参照されるか、新たに追加された

safe
キーワード(コンパイラが明示的な選択を要求する文脈のために導入)が付加されない限り那樣ではありません。このモデルの下では、囲う
unsafe { }
ブロックなしで unsafe メンバーを呼び出すと、警告ではなくコンパイルエラーが発生します。また、呼び出し側の義務を定義するために安全性ドキュメント(
/// <safety>
ブロック)の記述が必要です。この機能は .NET 11 でオプトインのプロパティを通じたプレビューとして提供され、将来的にはデフォルトになる可能性があります。機械的な書き換えについては
dotnet format
ツールによる対応が可能ですが、リフレクションや隠れた依存関係を含む複雑なシナリオでは依然として手動での介入が必要です。結局のところ、チームはこれらの厳格なコンパイラチェックを満たすため、一般プロダクション導入の前にinterop呼び出しを積極的に更新し、重要なロジックをラップする必要があります。

本文

C# 16 と unsafe キーワードの刷新:メモリ安全性の飛躍的向上について

はじめに

C# では、メモリ安全性を大幅に強化するための工程が進行中です

unsafe
キーワードは、呼び出し元に安全を保証するために満たすべき義務があることを明示するため、再設計されています。その責務は、新しいセーフティ(安全性)コメントスタイルを用いて文書化されます。

  • 範囲の拡大: かつてポインタだけをマークするものから、コンパイラが安全性を検証できない手法でメモリと相互作用するコード全体をカバーする範囲へと拡大しました。
  • 強制カプセル化: コンパイラは、
    unsafe
    キーワードを使用して非安全な操作をカプセル化するのを強制します。これにより、セーフティ契約や仮定が黙示的ではなく、可視化されレビュー可能になります。
  • 実装スケジュール:
    • 新モデルと構文は .NET 11 プレビュー版で先行実装として登場。
    • .NET 12 で正式にリリースされる予定です。
    • 初期段階ではオプトイン(オプション)方式ですが、その後のリリースではデフォルトの設定になる可能性があります。
  • テンプレートの更新: nullability(null 許容性)の参照型と同様に、新しいモデルを有効にするためのテンプレートも更新されています。

C# 1.0 の unsafe とその背景

C# 1.0 では、

unsafe
キーワードはタイプ、メソッド、および内部メソッドブロックへの不安全なコンテキストを設定する方法として導入されました。

  • 従来の仕様:
    • 開発者は最も都合の良いスコープを選択できるように設計されていましたが、非安全なコンテキストにはポインタ機能へのアクセス権が与えられました。
    • メソッドが
      unsafe
      でマークされている場合、その署名と実装でこれらの機能が使用できます。
    • システムライブラリ(例:
      System.Runtime.CompilerServices.Unsafe
      Marshal
      )も「unsafe」コンテキストに明示的に含まれていました。
  • C# 16 の方向性:
    • Rust や Swift が
      unsafe
      を再活用・拡張してきたような厳格で伝播指向の意味を採用しました。
    • .NET ランタイムライブラリを含めて 
      Unsafe
      および
      Marshal` のメンバーにも一貫して unsafe な性質を適用します(Rust の実装に最も類似)。
    • 「unsafe は単なる構文マーカーではなく、コンパイラが検証できない一種の契約であり、熟練した開発者が意識し、遵守する必要があるものへと変化しました」。

C# はすでにデフォルトで unsafe なコードをブロックしています。新しいモデルが有効になっても、unsafe API を使用しない開発者にとっては大きな変化はありません。しかし、デフォルトでブロックされる領域は大幅に拡大します。

背景と目的:

  • メモリ安全性は、数年間にわたり業界や政府において優先事項として高まってきました。
  • AI 支援によるコード生成の登場により、ソフトウェア生産が人間によるレビューのペースを超えて急速に拡大しています。これに対応すため、新しいモデルは可視化されレビュー可能でコンパイラによって強制される強力なガードレールを確立します。

セーフティと構造

より詳細なセーフティメカニズムについては、「.NET とは何で、なぜ選ぶのか」を参照してください。

セーフティの定義:

  • 言語とランタイムの組み合わせによって強制される強制力。
  • 変数はライブオブジェクトを参照するか null かスコープ外である。
  • メモリはデフォルトで自動初期化され、新しいオブジェクトは未初期化のメモリを使用しない。
  • 境界チェック: 無効なインデックスへのアクセスが未定義のメモリの読取(オフバイワンエラーなど)を許容せず、代わりに
    IndexOutOfRangeException
    を発生させる。

C# は通常 safe なコードに対して強いセーフティ強制を提供します。新しいモデルは、開発者と AI エージェントが unsafe なコードにおける安全の境界を正確にマークすることを可能にします。

  • unsafe の理由:
    1. ネイティブコードとの相互運用性
    2. パフォーマンス(場合による)
  • 役割の明確化: 言語自体は通常、unsafe なコードの作成を支援することはできません;その役割は、unsafe なコードがどこで使用されているか、安全なコードに戻る方法かを明確にすることです。

プログラミングの安全性を理解する別の見方:

  • 道路設計: 対向車線への進入禁止(黄色・白線)や、健全なコンプライアンスがない場合でも機能する構造的分離(バリヤ)。
  • メモリ分野特有の事故: すべてのアプリケーションはギガバイト単位の変数メモリへのアクセスが可能です。任意のメモリの書き込みまたは読み取りは**未定義の振る舞い(UB)**を引き起こし、最も一般的なセキュリティバグの原因となります。

モデルの概要

.NET プログラムは、すべてのメモリアクセスがライブメモリ(割り当てられ、初期化され、アクセス時点で使用可能なメモリ)をターゲットにするというコア不変条件を守ることを期待します。

  • 安全なコード: コンパイラルールとランタイムチェックの組み合わせにより、迷いのあるアクセスは不可能になります(構造的に守る)。
  • unsafe なコード: 不変条件を違反する可能性がある操作です(割り当てられていないメモリまたは初期化されていないメモリへのアクセスなど)。

リスクに対する解決策: 意図的に透明性の高い層状メカニズム。これにより call graph(呼び出しグラフ)を通じて unsafety が推進され、各層が次の層を可能にします:

  1. Inner unsafe { } ブロック:
    • すべて unsafe な操作(unsafe メンバーへの呼び出し、ポインタの参照解除など)は、内部
      unsafe { }
      ブロック内に表示する必要があります。
  2. 伝播 (Propagation):
    • 内部ブロックの義務を呼び出し元に再公開するには、囲むメソッドの署名に
      unsafe
      を追加します。
    • これにより、安全なメソッド、unsafe なメソッド、および境界メソッドで呼び出しグラフが分離されます。開発者は任意の数の上流で連鎖的に伝播させることができます。
  3. セーフティドキュメント:
    • 各 unsafe メンバーは
      /// <safety>
      ブロックを持つべきです。これは形式的契約です。
    • アナライザがその欠如をフラグ立てます。
  4. 境界での抑制 (Suppression at the boundary):
    • 内部 unsafe ブロックを含みながら署名に
      unsafe
      をマークしないメソッドは、安全なコードと unsafe なコードの境界です。
    • ランタイムガード、静的推論、または上流 API から得られた文書化された不変条件を通じて解除します。

重要な原則: 各層を順番にステップして価値を得なければなりません。半分の作業をするだけで半分以下の価値しか得られません。これにより、call graph を通じて他者がレビューし潜在的に改善できる接続された推論ラインを持つことができます。

C# 16 における変更点(C# 1.0 のルールから)

C# 1.0 はポインタ機能などをまとめて「ポインタ機能」として unsafe の下にグループ化していました。新しいモデルはより選択的です。主な変更点は以下の通りです:

  • unsafe タイプ修飾子: エラーを発生させます。unsafe スコープはタイプから個別のメソッド、プロパティ、フィールドへと移動し、その契約が見え見えになり最小限に特定されます。
  • 静的コンストラクタまたはファイナライザーへの適用: 許可されません(署名マーカーは何ものにも伝播できないため)。
  • new() ジェネリック制約: パラメータなしの安全なコンストラクタだけを一致させます。パラメータなしコンストラクタが unsafe なタイプは
    new()
    を満たすことができません。
  • 新しい safe キーワード: デクレレーションが安全であることを証人する開発者への許可(コンパイラが選択を明示的に要求する場所)。現在、
    extern
    宣言だけです。
  • メンバー上の unsafe: 危険なコンテキストを確立し、もはや「不安全なタイプ」を意味しません。内部 unsafe ブロックが unsafe コールサイトを必要とします。
  • ポインタタイプへの伝播の停止: 署名でのポインタタイプはもはや unsafety を伝播しません(独自に
    byte*
    パラメータは呼び出し元に unsafety を伝播しません)。新しいコードでは
    IntPtr
    の代わりに typed pointers(例:
    byte*
    ,
    void*
    )を好みます。

プロジェクトレベルのオプトイン

C# 16 セーフティモデルには 2 つのプロジェククト(プロジェクト)レベルスイッチがあります。それらは独立しており、異なる目的を担います。

スイッチの詳細

  1. 新しいオプトインプロパティ (
    .NET 11
    プレビューで最終名が決定):
    • オフ: レガシー C# 1.0 のルールが引き続き支配されます。
    • オン: 新しい呼び出し元 unsafe ルールが適用されます(何が unsafe なカウントされ、どのように伝播するかを決定)。
  2. 既存の
    <AllowUnsafeBlocks>
    プロパティ
    :
    • すべての C# バージョンでデフォルトは
      false
      です。
    • プロジェクトソース内の
      unsafe
      キーワードの出現をゲートします(メソッド署名、内部ブロック、フィールドなど)。
    • 別のプロジェクトから unsafe API を呼び出す場合もカウントされます;呼び出しサイトには内部
      unsafe { }
      ブロックが必要です。

スイッチ組み合わせの影響

設定状態説明
新プロパティオン +
<AllowUnsafeBlocks>
オフ(デフォルト)
最も安全新モデルに参加しますが、unsafe なコードを許可しません。
Marshal.ReadByte
などの呼び出しはエラーになります。
新プロパティオン +
<AllowUnsafeBlocks>
オン
安全な開発環境新モデルに参加し、unsafe なコードを許可します。
新プロパティオフ +
<AllowUnsafeBlocks>
オフ
レガシーモード(禁止)レガシーモデルが引き続き適用されますが、ポインタタイプを使用できません。
新プロパティオフ +
<AllowUnsafeBlocks>
オン
レガシーモード(許可)レガシーモデルが引き続き適用されます。ポインタタイプを使用できます。

移行支援: 機械的再書き換えを行う

dotnet format
修正ツールが発売予定です。ただし、修正ツールは安全性義務を推論したり
<safety>
ブロックを書いたりすることはできません;それは開発者の仕事です。

エージェントへの影響:

  • 新モデルでは、コンパイラが unsafety の責任を負います。
  • AllowUnsafeBlocks=true
    を設定していない場合、コンパイラは安全ではないコードそのものをコンパイルを拒否します。
  • メモリ安全性監査は、すべての diff を検査することからチェックプロジェクトプロパティ 1 つに縮小されます。

クロス言語比較:伝播

C#、Rust、Swift の間の違いは微細ですが重要です。

  • C# 16: unsafe キーワードがメンバー上に現れる場合のみ unsafety を伝播します(ポインタタイプや他の unsafe タイプ付きパラメータは独自に伝播しません)。
  • Rust: 通常の
    fn
    *const u8
    パラメータは何も伝播しません。
    unsafe fn
    は unsafe ブロック内にある safe fn を超えており、デフォルトが unsafe で safe が個別のデクレレーションをオプトアウトする形は Swift の
    @safe
    に類似しています。
  • Swift: 例外です。署名内に
    @unsafe
    タイプが出現するだけで、デクレレーション自体を
    @unsafe
    にし、明示的な
    @unsafe
    属性とは別にします。このインプリシティブ(暗黙的)モデルは、opt-out (
    @safe
    ) の必要性をもたらします。

LibraryImport の例: 各 LibraryImport パシャルメソッドは safe または unsafe とマークする必要があります:

[LibraryImport("libc")]
internal static safe partial int getpid(); // 安全な呼び出し

[LibraryImport("libc", StringMarshalling = StringMarshalling.Utf8)]
internal static unsafe partial nint strlen(byte* str); // unsafe な呼び出し

getpid
はパラメータなしで primitives を返すため safe であり、
strlen
は生ポインタを収容するため unsafety を伝播します。両方の修飾子を省略するのはコンパイラエラーです。

セーフティドキュメント(コメントスタイル)

「unsafe」を文字通りに解釈することは簡単ですが、誤解を招きます。「安全無効化」を意味します。safe なコードはコンパイラに知られたセーフティモデルに準拠しているのに対し、unsafe なコードにはありません。知る重みが開発者にあります。それは専用セーフティドキュメントを読むことで始まります。

コメントスタイルの役割

  • 署名上の
    /// <safety>
    ブロック
    : 形式的呼び出し元契約です。
  • ボディ内の
    // SAFETY:
    コメント
    : 内部的な注記であり、unsafe な操作が依存するものを名前付けます。

教訓: unsafe API の形状を知るのは正しいコードを書くために必要ですが十分ではありません。unsafe なコードを書くことにはセーフティグラスが必要です。

Rust セーフティコメントの例

Rust は確立された標準的な例です。Clippy はセーフティブロックがない unsafe 関数に対して

missing_safety_doc
lint をトリップします。

// unsafe Rust 関数、as_bytes_mut:
/// Converts a mutable string slice to a mutable byte slice.
///
/// # Safety
///
/// The caller must ensure that the content of the slice is valid UTF-8
/// before the borrow ends and the underlying `str` is used.
///
/// Use of a `str` whose contents are not valid UTF-8 is undefined behavior.
///
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
    // SAFETY: ... (internal note)
    unsafe { &mut *(self as *mut str as *mut [u8]) }
}

C# セーフティコメントの例

以下の ReadByte モックアップを参照:

/// <summary>Reads a single byte from unmanaged memory.</summary>
/// <safety>
/// The sum of <paramref name="ptr"/> and <paramref name="ofs"/> must address a byte
/// the caller is permitted to read.
/// </safety>
public static unsafe byte ReadByte(IntPtr ptr, int ofs)
{
    try
    {
        byte* addr = (byte*)ptr;
        unsafe
        {
            // SAFETY: relies on caller obligation.
            return addr[ofs];
        }
    }
    catch (NullReferenceException)
    {
        throw new AccessViolationException();
    }
}

セーフティガード

ドキュメントは義務を名前付けます。ガードはそれらを解除します。このパターンは最も unsafe 境界で重要です。

Rust セーフティガード例

str.split_at
の例:

pub fn split_at(&self, mid: usize) -> (&str, &str) {
    // is_char_boundary checks that the index is in [0, .len()]
    if self.is_char_boundary(mid) {
        // SAFETY: just checked that `mid` is on a char boundary.
        unsafe { (self.get_unchecked(0..mid), self.get_unchecked(mid..self.len())) }
    } else {
        slice_error_fail(self, 0, mid) // パニック(コンパイラエラー回避のため)
    }
}

C# セーフティガード例

同じ境界パターンが C# で適用されます:

public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
{
    ArgumentNullException.ThrowIfNull(destination);
    ArgumentOutOfRangeException.ThrowIfNegative(count);
    // ... 他のチェック ...

    unsafe
    {
        // SAFETY: 上記の境界チェックにより、`count` キャラクタが安全であることが保証される。
        Buffer.Memmove(...);
    }
}

ThrowIf*
コールはメモリ安全性ガードであり、生
Buffer.Memmove
が仮定する不変条件を支えます:

  • ThrowIfNull(destination)
    : 欠如すると UB。
  • ThrowIfNegative(count)
    : 欠如すると out-of-range コピーが UB。
  • インデックスの符号チェック:欠如すると UB。

Unsafe フィールド

フィールドは、声明されたタイプが保持する不変条件とダウンストリームコードが依存する不変条件の間にあるギャップがある場合に unsafe な必要があります。unsafety は、型システムが見ることと外部のタイプの約束との間に住んでいます。

ネイティブポインタ保持フィールドの例

public class NativeBuffer : IDisposable
{
    /// <safety>
    /// Must be null or point to a buffer of Length bytes.
    /// </safety>
    private unsafe byte* _ptr;

    public void Dispose()
    {
        unsafe
        {
            // SAFETY: ... Free accepts both null and valid pointers.
            NativeMemory.Free(_ptr);
            _ptr = null;
        }
    }
}

ジェネリック配列ラッパーの例

設計ドキュメントは簡易版を与えます:ジェネリッククラスは常に

T[]
を含んでいる必要がある Array フィールドを持ちます。C# 型システムは任意の配列をそのフィールドに割り当てを許可しますが、クラスは常に正確な
T[]
を約束しています。unsafety はそこにあるギャップです。

public class ArrayWrapper<T>
{
    /// <safety>
    /// Must always hold a value whose runtime type is T[].
    /// </safety>
    private readonly unsafe Array _array;

    public T GetItem(int index)
    {
        unsafe
        {
            // SAFETY: _array is always a T[] per the field's <safety> block
            var typedArray = Unsafe.As<T[]>(_array);
            return typedArray[index];
        }
    }
}

パターンは NativeBuffer と同じです:文書化された不変を持つ unsafe フィールド境界でそれを解除する unsafe ブロックsafe-callable パブリック表面

マイグレーション事例の walkthrough

モデルを理解するための最良の方法は、既存のコードをそれに移行することです。

NativeMemory の例

新モデル下での 2 つの NativeMemory メソッドの外観:

public static void* Alloc(nuint byteCount); // safe (returns pointer, holding it is not unsafe)

/// <safety>
/// The caller must ensure:
/// - ptr was returned by Alloc(...) and has not already been freed.
/// - No live pointer/span aliases the storage at this call time.
/// </safety>
public static unsafe void Free(void* ptr); // unsafe (has preconditions)

非対称性の意図:

  • Alloc
    は safe になります。ポインタを保持する自体は unsafe ではありません;unsafety は最終的な解除参照にあり、呼び出し元がラップします。
  • Free
    は unsafe remians(残存)因为 it carries real preconditions(pointer must be valid and not freed);the
    <safety>
    block makes those obligations visible.

バイナリ配布とコンパチモード

.NET ライブラリは頻繁にバイナリとして配布されます。C# 16 unsafe は新しいコンパイラエラーに大きく依存します。新モデルへのオプトインでは、注釈作業は完了しています。

非対称な互換性

旧モデルでコンパイルされたプロジェクトが新モデルで作成されたパッケージを消費し、その逆も起こります:

  1. オプトイン側 (caller) vs レガリー側 (callee):
    • オプトイン側のプロジェクトはレガシーパッケージに対して compat-mode ルールを強制します。
    • callee 署名内の任意のポインタタイプは呼び出しサイトで囲む
      unsafe { }
      ブロックを要求します。
  2. レガシー側 (caller) vs オプトイン側 (callee):
    • レガリープロジェクトはオプトインパッケージを普通のアセンブリとして扱い、新しい診断の対象になりません。

理由: オプトイン側がセーフティ保証を負うため、compat モードはそれを静かに劣化させないことを保持します。

残り設計領域

C# 16 では扱えなかったいくつかの設計側面があります。今後のバージョンで扱う可能性があります。

  • リフレクション:
    MethodInfo.Invoke
    を通じて unsafe API を呼び出すことができ(囲む unsafe ブロックなし)、リフレクション書き込みは unsafe フィールドの文書化された不変条件を違反できます。
  • ライフタイム: Rust は borrow checker でライフタイムを扱います;C# は GC と ref ベースの所有権の一部をカバーします。より強いライフタイム強制の主要なユースケースは
    ArrayPool
    、特に
    Rent
    Return
    メソッドです(「使用後自由」違反)。

AI 支援(AI Enablement)

モデルはエージェントが無視できない 2 つのものを追加します:

  1. 安全/unsafe/境界メソッドに分割された call graph。
  2. 囲む unsafe ブロックなしに unsafe コールを拒絶するコンパイラ。

アナライザも

<safety>
ドキュメントの欠如のための警告に貢献します。これらは、エージェントが生成できるコードを狭めると同時にビルドを幸せに保ちます(特に
TreatWarningsAsErrors
が設定されている場合)。

エージェントがモデルを侵犯する 2 つの主要な方法

  1. コンパイルしないコードを生成する
  2. プロジェクトを旧モデルに戻したり、AllowUnsafeBlocks を有効にする。(これは
    TreatWarningsAsErrors
    IsAotCompatible
    を無効にしたい場合と同じ)。

両カテゴリーはコードレビューや git 履歴で容易に検出できます。新モデルへの移行もエージェントに適しています。

Rust(

unsafe fn
,
unsafe {}
)に確立されたパターンは C# 型のコードに綺麗にマッピングします。最も高価なパターンマッチはセーフティドキュメントの構造とイディオムです;その移行側が最も困難にスキル化され得ます。

結論

新しいモデルは、unsafe コードを使用するコードの上に opt-in の壊れ変更を一連レイヤーします:

  • メンバー署名上の unsafe が呼び出し元向け契約を定義し、
  • 各 unsafe メンバーへの呼び出しには内部 unsafe ブロックが必要で、
  • 各 unsafe メンバーは
    /// <safety>
    ブロックを持つべきです。

我々は C# が型およびメモリセーフティ強制を選択・記載された一連言語の中にあり得る未来を思い描いています。このモデル変更により、C#、Rust、Swift はより共通なセーフティボキャブulario ワークフローを持ちます。チームは完全なサプライチェーン視点を依存関係(C# まで下ろすか、app レイヤー C# を system レイヤー Rust の上で)採用します。

新しいモデルは C# をほぼそのまま保ちながら、開発者がほとんど触れない unsafe パターンを微調整し、言語全体の安全能力と姿勢を大幅に改善します。我々はこの機能が、この新しいコーディング時代における開発者の信頼を高めるためにできる最も高いレバレッジの変更の一つであると信じています

カテゴリ・トピック

カテゴリトピック
AuthorRichard Lander は .NET チームのプログラムマネージャーです。メモリ制限のある Docker コンテナ、Arm ハードウェア(Raspberry Pi など)、GPIO プログラミングおよび IoT シナリオでの .NET の機能向上を担当しています。新しい .NET ランタイム機能と機能を定義する設計チームの一員でもあります。

趣味: Dune と Doctor Who が好き。カナダとニュージーランドで育ちました。
ContributorsAndy Gocke, Egor Bogatov, Fred Silberberg, Jan Jones, Jan Kotas, Julien Couvreur, Mads Torgersen, Rich Lander, Tanner Gooding ほか

同じ日のほかのニュース

一覧に戻る →

2026/05/24 3:45

私の Writerdeck を語る時が来ました。

## 日本語翻訳: 著者は、6年経った System76 Galago Pro ラップトップを「writerdeck」と名づけたオフライン書写ステーションに変換し、X11、Wayland、およびデスクトップ環境を排する tty ベースの構成で Debian Trixie を実行することでミニマリズムを優先しています。コンテンツが公開共有を目的としているためフルディスク暗号化は省略され、管理には `sudo` ユーザーモデルに切り替えて root ログインが無効化されました。本質的なツールとして、Neovim がテキスト編集に使用され(従来のエディタに代わり)、Debian バックポートからの `kmscon` でスケーラブルなターミナルウィンドウを可能にし、セッション多重化には `tmux` を使用し、インストール済みの Network Manager 経由の `nm-tui` が Wi-Fi/WAN の管理に用いられます。電力モニタリングおよび画面明るさ制御は `acpi` と `light` コマンドで行われ、自動ログインと `.bashrc`内の起動スクリプトにより Neovim が `tmux` セッション内で動作し、ブート時に Vimwiki が起動するようにしています。Syncthing は Vimwiki フォルダをリモートサーバーに同期させ、ブラウザ GUI を必要とせずオフラインファーストなワークスペースを維持するために全てのネットワークアドレスを活用しています。この構成はデジタルの雑多さを削減し、悪い書写習慣を打破助けるとともに、クリエイティブ専門家にとってセキュリティと生産性を向上させます。

2026/05/24 7:25

自分でロールを作るな

## 日本語訳: 要約: 開発者は、暗号化やユーザーインターフェースコンポーネントといった重要な機能に対して独自の実装を即時に停止する必要があります。なぜなら、「自分自身でつくる」というソリューションは過去の実績が証明する通り危険であるためです。最も重要な教訓は、安全性と使い勝手を確保するために、自作コードの代わりに既成でピアレビューされた標準を採用しなければならないことです。独自のカスタム暗号化パッケージには、初期化の不備や予測可能なパターンなどの深刻な欠陥を内包しており、規制産業では財務規制に違反し、高額の罰則を引き起こす可能性があります。セキュリティの問題だけでなく、ネイティブブラウザ要素を置換することは性能低下をもたらし、過剰な JavaScript ロジックによりキーボードスクロールの破損やリンクの読み込み遅延といった問題を引き起こします。さらに、独自のソリューションは自動入力機能など、安全なパスワード管理などの重要なネイティブ機能を排除してしまいます。この傾向は、組み込みブラウザ機能の安定性よりも創造的なツールの構築を優先しており、ユーザー(高齢者のご家族も含まれます)が慣れ親しんだツールを常に再学習することを強いられています。これらの使い勝手に関する落とし穴を防ぎ、規制当局による罰金を避けるためには、開発者はネイティブ要素を置換するのではなく補完する方向へ転換すべきです。これにより、すべてのウェブサイトで一貫した動作を確保できます。

2026/05/21 6:21

私の二画面デスクセットアップ(2025)

## 日本語訳: 著者は、壁を向いた単調なパソコンデスクを部屋の方を向くように回転させることで(ドアを見渡させ、奥行きを追加)、そしてテック専用だった単一の面を、二つの明確なゾーニングに分かれた大規模な USM ハラーデスクに置き換えることにより、ハイブリッドなワークスペースへと成功裡に変化させています。このデザインは、ソーシャルメディアでのフィードバックを受けてから以前の壁を向いた配置が持っていた「古い」外観に対応し、また、未使用のアイテム、おもちゃ、プロジェクトをアナログ側の面に置き続けることで、ストイックなミニマリズムの限界を解決し、アイデアを刺激することを可能にしています。単純にチェアを二つの半分の間で移動させることで強化された明確な精神的境界線により、このセットアップは一つの表面上で「作業」「思考」「子供たちと過ごす時間」という 3 つの異なる機能を発揮します。9 ヶ月の使用後、著者は単一コンピューターの配置に戻る予定はないことを確認しており、むしろミニマリスト的な規律とマキシマリスト的な柔軟性を融合させたこの柔軟なシステムを維持する意欲を持っています。これにより、別々の部屋を必要とせずに、ワークフローと創造的アウトプットを向上させることができます。