Journal

Goで書いた小さなCLIが、毎朝ちゃんと残る理由

朝いちばんに使う道具は、派手なものより、気配が薄いもののほうが残ります。私の環境だとそれが、ダウンロードフォルダを新しい順に5件だけ出すGoの小さなCLIです。やっていることは地味です。けれど、毎朝ほぼ反射で叩いています。

理由は単純で、便利だからでは足りないからです。便利なだけの道具は、意外と消えます。起動が遅かったり、配布が面倒だったり、設定ファイルが散らかったり、アンインストールが重かったりします。そのどれかがあるだけで、数日は触っても、そのうち机の隅へ寄っていきます。

この手の補助ツールは、機能より先に後始末の軽さが効きます。置くのも簡単、消すのも簡単、挙動も読めます。その条件を満たすと、ようやく習慣に入ってきます。Goで書いた単体バイナリのCLIは、その条件にかなり素直です。

何をするツールか

私が朝に見たいのは、ダウンロードフォルダの全体像ではありません。直近で何が落ちてきたかだけです。夜のあいだに保存したzipや、ブラウザが勝手に置いたインストーラや、名前の似た画像だけ見えれば十分です。

そのため、出力も5件で止めています。10件だと少し多いです。3件だと取りこぼします。こういうところはアルゴリズムの話ではなく、手癖の話だと思います。

コードはこれだけです。

package main

import (
    "fmt"
    "os"
    "path/filepath"
    "sort"
    "time"
)

type entry struct {
    name string
    mod  time.Time
}

func main() {
    home, err := os.UserHomeDir()
    if err != nil {
        panic(err)
    }

    dir := filepath.Join(home, "Downloads")
    items, err := os.ReadDir(dir)
    if err != nil {
        panic(err)
    }

    rows := make([]entry, 0, len(items))
    for _, item := range items {
        info, err := item.Info()
        if err != nil {
            continue
        }
        rows = append(rows, entry{
            name: item.Name(),
            mod:  info.ModTime(),
        })
    }

    sort.Slice(rows, func(i, j int) bool {
        return rows[i].mod.After(rows[j].mod)
    })

    limit := 5
    if len(rows) < limit {
        limit = len(rows)
    }

    for _, row := range rows[:limit] {
        fmt.Printf("%s\t%s\n", row.mod.Format("2006-01-02 15:04"), row.name)
    }
}

なぜこれが残るのか

このくらいの道具だと、正直、AIに下書きだけさせても作れます。けれど、そのあとが大事です。どこまで絞るか、何件だけ出すか、時刻をどう見せるか、例外をどこで握りつぶすかまで含めて、その細部には使う本人の癖がそのまま出ます。フレームワークを積んだ瞬間に、その癖が遠くなります。

私は最近、AIにはボイラープレートだけ任せるほうが気が楽です。考えなくていい部分は渡します。でも、毎日触る道具の輪郭までは渡しません。そこを渡すと、自分の手に馴染む前に、ただの「生成された何か」になります。

Goがこういう用途で強いのは、コードがきれいに閉じるからです。標準ライブラリだけで終わることが多いですし、配るときも説明が要りません。zipを展開してexeを置けば終わり、という雑さがそのまま強さになります。私はGoをかなり現代のC言語として見ていますが、こういう小道具を書くときにその感覚がいちばんよく出ます。

もちろん、何でもCLIにすればよいわけではありません。毎回オプションを思い出す必要があるものは続きません。出力が長すぎるものも続きません。続くのは、見たいものだけが一瞬で返る道具です。

Dockerで動作確認した結果

上のコードは、Linuxコンテナの中でサンプルのDownloadsディレクトリを作って確認しました。6個のファイルを置くと、新しい順に5件だけ表示されます。ホスト側の既存ファイルは触っていません。

確認に使ったコマンドはこれです。

docker run --rm -v "$PWD":/work -w /work golang:1.25 sh -c '
set -e
mkdir -p /tmp/home/Downloads
printf hello >/tmp/home/Downloads/sample.txt
touch -t 202607160730 /tmp/home/Downloads/sample.txt
touch -t 202607160731 /tmp/home/Downloads/old.zip
touch -t 202607160732 /tmp/home/Downloads/browser.exe
touch -t 202607160733 /tmp/home/Downloads/image.png
touch -t 202607160734 /tmp/home/Downloads/note.md
touch -t 202607160735 /tmp/home/Downloads/go1.25.tar.gz
touch -t 202607160736 /tmp/home/Downloads/extra.iso
HOME=/tmp/home go run main.go
'

この確認をわざわざ入れるのは、技術記事でいちばん寒いのが、書いた本人も動かしていないコードだからです。AIがそれっぽい断片を出すのはもう珍しくありません。だからこそ、短くても自分で動かしたほうが早いですし、そのほうが文章にも変な力みが出ません。

自分のPCにあるソフトウェアくらい、自分で触って、自分で確かめたほうがいいです。大げさな話ではありません。朝に使う小さな道具ほど、その感覚がそのまま効きます。

Previous