すべての記事

ファイラーを作って分かったこと── Undo は嘘をつく。だから言語を選び直す

ファイラーを作って分かったこと── Undo は嘘をつく。だから言語を選び直す

ファイラーを作って分かったこと
── Undo は嘘をつく。だから言語を選び直す

きっかけは単純だった。Windows のエクスプローラーは優秀だが、「考えながら操作する」には少し重い。ならば、自分の思考速度に合わせた TUI ファイルエクスプローラ を作ってみよう。そんな軽いノリで始めた。

Python と Textual を使い、移動・検索・コピー・ペースト・リネーム・削除・Undo・外部起動まで一通り実装した。動いた。それなりに快適だった。

そして最後に、致命的な違和感だけが残った。


Undo は「戻せるふり」をする

Undo は Command Pattern で実装した。execute()undo() を対にし、スタックに積む。教科書的には正しい。

Command Pattern の実装

class Command:
    def execute(self):
        raise NotImplementedError

    def undo(self):
        raise NotImplementedError


class RenameCommand(Command):
    def __init__(self, old_path: Path, new_path: Path):
        self.old_path = old_path
        self.new_path = new_path

    def execute(self):
        self.old_path.rename(self.new_path)

    def undo(self):
        self.new_path.rename(self.old_path)


class CopyCommand(Command):
    def __init__(self, src: Path, dest: Path):
        self.src = src
        self.dest = dest

    def execute(self):
        if self.src.is_file():
            shutil.copy2(str(self.src), str(self.dest))
        else:
            shutil.copytree(str(self.src), str(self.dest))

    def undo(self):
        if self.dest.is_file():
            self.dest.unlink()
        else:
            shutil.rmtree(self.dest)

だが、実際に触ると分かる。

ファイルは外部からも変更される

同名ファイルはいつの間にか増える

削除は「ゴミ箱行き」だが Undo 不能

OS が勝手に状態を変える

つまり Undo はこうなる。

「戻れる時だけ戻れる。でも UI はそれを教えてくれない」

これは UX の問題ではない。設計上の嘘だ。

Undo が壊れるのは、コードではなく "世界の状態"が変わるからだ。


Python は悪くない。ただ"黙認する"

今回の実装で Python が悪かったわけではない。むしろ良かった点は多い。

試作が異常に速い

OS API を雑に叩ける

書いている間に思想が固まる

ただし、ある段階から気づく。

Python はこう言っている。

「それ、本当に考えた?まあ、動くなら止めないけど」

Undo実装の実際

def action_undo(self):
    if not self.command_stack:
        self.update_status("⚠️ Undoできる操作がありません")
        return

    cmd = self.command_stack.pop()
    try:
        cmd.undo()
        self.reset_tree()
        self.update_status("↩️ 操作を元に戻しました")
    except Exception as e:
        self.update_status(f"⚠️ Undo失敗: {e}")

例外は握り潰せる。状態はぐちゃっと持てる。Undo も「たぶん大丈夫」で通る。

Python は自由をくれる。ただし、責任を強制はしてくれない

思考実験には最適だが、責任を持つ設計には沈黙する。


作って初めて見えた"設計の層"

このファイラーは、実は3層でできている。

1. OS直叩き層

  • ファイル操作、クリップボード、フォーカス制御
  • ここは OS の気分に左右される

2. UI / 状態管理層

  • モード遷移、履歴、入力状態
  • ここは Python と Textual が得意

3. 事故制御層

  • 失敗、部分成功、Undo 不能、競合
  • ここが最も重要で、最も軽視される

Undo が嘘をつくのは、この 「事故制御層」を設計していないからだ。


では、次に選ぶべき言語は何か

今回の経験で分かったのは、言語選択は性能ではなく 思想の選択だということ。

C#

Windows を母国語として扱える。例外と型で「失敗理由」を持てる。今回のコードを最短で"格上げ"するならこれ。

Rust

Undo が嘘をつく余地をコンパイル時に潰してくる。書くのは重いが、事故の設計から逃げられない。これはツールではなく、思想の実装。

TypeScript + Tauri/Electron

UI/UX は別次元。ただし低レイヤは Rust/C++ に戻る。「使う人の認知を支配したい」なら最強。

Go

無骨で、並行性が素直。内製ツールとしては非常に強い。

どの言語を選ぶかは、どの嘘を許容するかの選択でもある。


このプロジェクトの"役目"はもう終わった

この Python ファイラーを完成させるつもりはない。役目はもう果たした。

Undo は簡単ではない

ファイル操作は外界と競合する

「動く」と「責任を持てる」は別物

これらを 体感できる形で可視化してくれた。

次にやるなら、

言語を変える

Undo を"戻せないことがある"前提で設計する

失敗を UI に出す

そのどれか、あるいは全部だ。


おわりに

このファイラーは売り物ではない。だが、無駄でもない。

作った結果、「どこからが嘘になるか」が分かった

それだけで十分に価値があった。

技術は、完成品よりも "完成できない理由"を教えてくれる時の方が、ずっと誠実だ。


📦 ソースコード

この記事で言及したファイラーの完全なソースコードは GitHub で公開しています。

View on GitHub →