FLINTERS BLOG
🗒️

凝集性を意識したdotfiles運用

に公開

こんにちは、FLINTERSの笠本です。

この記事はアドベントカレンダー19日目の記事です。

dotfilesを触っていて、こんな感覚を持ったことはありませんか。

  • 変更自体は小さいのに、やけに面倒に感じる
  • 触る前に「ちょっと気合い」が必要
  • 何かを追加するたびに、どこを直せばいいか一瞬考える

はっきりとした不満があるわけではない。 でも、なぜか触りたくない。

自分の場合、その原因はしばらく分かりませんでした。
設定はちゃんと動いているし、破綻もしていない。
dotfilesなんて、こんなものだろうと思っていました。

ただ、ツールを追加するたびに、毎回こうなっていました。

致命的ではありません。
でも、「あれ、これどこだっけ?」が確実に発生する。

  • aliasはどこに書いた?
  • install時にconfigのコピー必要だった?
  • この設定、まだ使ってる?

この小さな思考停止の積み重ねが、 無意識のストレスになっていると気づきました。
この時、1つの機能 / ツールに関する関心事が、あちこちに散らばっていたことから、これは凝集性の低さが原因だろうと考えました。

そこで、dotfilesの構成を 「凝集性を上げる」 という観点で組み直してみました。

この記事では「どう構成を変えたか」「それによって何が楽になったか」を紹介します。

※この記事で紹介している dotfiles 全体はこちら
👉 https://github.com/onigiri-w2/dotfiles

どう変えたのか

取り入れた考え方は、とても単純です。

機能的凝集 ── 関連するものは、1箇所にまとめる

dotfilesにも、この考え方をそのまま適用しました。

具体的には、
1つの機能 / ツールに関するものを、すべて1つのフォルダに集約する
という構成にしています。

例えば nvim なら、こうです。

features/nvim/
 ├── install.zsh   # nvimのinstallや依存関係のセットアップ
 ├── shell.zsh     # alias、PATH、環境変数など
 └── config/       # 設定ファイル群

「nvimに関することを知りたければ、このフォルダだけ見ればいい」
その状態を作ることを最優先にしました。

install.zsh

brew install nvim
brew install ripgrep  # nvimの検索で使う
brew install lazygit  # nvim内のgit操作で使う

ln -sf "$DOTFILES/features/nvim/config/nvim" "$HOME/.config/nvim"

ポイントは、nvimが依存しているものを、すべてここに書くことです。
ripgrep や lazygit は他のfeatureでも使うかもしれません。
それでも気にしないことにしました。

「このパッケージ、誰が使ってるんだっけ?」と後から辿るより、
「nvimに必要なものは、nvimのフォルダに全部ある」
状態のほうが、理解コストが圧倒的に低いからです。

brew install も冪等なので、同じパッケージを複数のfeatureで書いても実害はありません。

ここでは DRYよりも凝集性を優先しています。

shell.zsh

alias v="nvim"
alias vim="nvim"

shell.zsh は、そのfeatureに関する「alias / PATH / 環境変数」などを書く場所です。

install.zsh とは、役割を明確に分けています。

・install.zsh → 一度だけ実行される処理  
・shell.zsh   → 毎回読み込まれるシェル設定  

全体の構造

全体はこうなっています。

dotfiles/
├── bootstrap.zsh     # .zshrcから読み込むエントリポイント
├── setup.zsh         # 初回セットアップ
├── shell.zsh         # グローバルなシェル設定
└── features/         # 機能ごとのフォルダ
    ├── nvim/
    ├── git/
    ├── tmux/
    └── ...

setup.zsh

新しいMacを使い始めるときに、1度だけ実行するスクリプトです。
全featuresの install.zsh を順番に実行します。
ここで必要なパッケージのインストールやシンボリックリンクの作成などをまとめて行います。

for feature in "$DOTFILES/features/"*/; do
    [[ -f "$feature/install.zsh" ]] && source "$feature/install.zsh"
done

bootstrap.zsh

シェル起動時に毎回読み込まれるスクリプトです。.zshrc から source します。
全featuresの shell.zsh を読み込んで、aliasや環境変数を設定します。

# bootstrap.zsh
for feature in "$DOTFILES/features/"*/; do
    [[ -f "$feature/shell.zsh" ]] && source "$feature/shell.zsh"
done

ルートの shell.zsh

特定のfeatureに属さない、グローバルな設定を書きます。
PATHの基本設定など、全体に影響するものだけを置いています。

ルートにあるファイルは
featuresを呼び出して束ねる役割で、
日常的に触るのはほぼ features/ 配下だけです。

得られた変化

構成を変えてから、dotfilesに対する感覚が明確に変わりました。

迷いが発生しなくなった

  • aliasはここ
  • installはここ
  • configはここ

考える前に場所が決まっているので、思考が止まらなくなりました。

「触るのが億劫」がなくなった

以前は、小さな変更でも「どこに影響があるか」を一瞬考えていました。

今は、そのツールのフォルダだけを見ればいいので、心理的なハードルがかなり下がりました。

「もう要らないかも」の判断がしやすい

使わなくなったツールは、features/ツール名/ を消すだけ。
設定が1箇所にまとまっているので、「どこかに残骸がありそう」という不安が減りました。
※ ただし、brewで入れたパッケージや設定ファイルは手動で消す必要があります。(後述)

Brewfileは使わない

恩恵は得ましたが、その裏で割り切っていることもあります。

Brewfileでの一括管理

各featureの install.zsh に brew install を直接書いています。
brew bundle は使っていません。

重複installは許容する

同じパッケージを複数のfeatureでinstallしている可能性はあります。
brewは冪等なので問題ありません。

ここでも DRYより凝集性を優先しています。

uninstall, cleanup は自動化しない

featureフォルダを消しても、brewのパッケージや設定ファイルは残ります。
なので、手動でクリーンアップ作業を行う必要があります。

ただし、ツールを消す頻度は低いので現状は手動で十分だと判断しています。

おわりに:凝集性は、思考コストを下げる

今回やったことは、
「dotfilesをモダンにした」「高度な仕組みを入れた」といった話ではありません。

ただ、
凝集性が低いと人は無意識にストレスを溜める
という説に立って、構成を組み直しただけです。

1つのツールに関する情報が分断されていると、以下のような小さな思考が発生します。

  • 探す
  • 思い出す
  • 確認する

それを 「このフォルダを見ればいい」 という状態にしただけで、dotfilesとの付き合い方がかなり楽になりました。

もし皆さんが今、dotfilesの管理に微妙なストレスを感じているなどある場合、もしやするとそれは低凝集が原因かもしれません。
暇な時間にこの観点で見直してみてるのはいかがでしょうか。

FLINTERS BLOG
FLINTERS BLOG

Discussion