ぜんぶかきなおす

丸2日くらいかけて、このサイトのHTML/CSSやサイト生成の仕組みを全部書き直した。わかりやすい変化としては、以前のバージョンではフォントサイズとか余白とかがビューポートのサイズに関わらずつねに一定だったところが、今のバージョンではビューポート幅にもとづいたファクターに応じてすべてのフォントサイズが変化するようになっている。

具体的には、まずビューポート幅にもとづいたファクターは次のように実装している。

html {
--scale-factor: 7;
}

@media (min-width: 331.2px) {
html {
--scale-factor: 6.99;
}
}

@media (min-width: 342.4px) {
html {
--scale-factor: 6.98;
}
}

@media (min-width: 353.6px) {
html {
--scale-factor: 6.97;
}
}

/* 同様に続く */

@media (min-width: 1417.6px) {
html {
--scale-factor: 6.02;
}
}

@media (min-width: 1428.8px) {
html {
--scale-factor: 6.01;
}
}

@media (min-width: 1440px) {
html {
--scale-factor: 6;
}
}

もっとも狭いビューポート幅では7になって、1440pxまで広がると6になる。そしてこれらの間の幅では間の値で補間される。メディアクエリで地道にやっているのがダサいけど、考え得る限りではこれが一番簡単になりそうだった。Sassを使えば楽に作れる

続いてこの値を用いて、調和数列にもとづいた計算方法でフォントサイズのスケールを定義する。モジュラースケールでもいいんだけど、問題は指摘されている通り

html {
--text-base: 1rem;
--text-sm: calc(var(--scale-factor) / (var(--scale-factor) + 1) * var(--text-base));
--text-lg: calc(var(--scale-factor) / (var(--scale-factor) - 1) * var(--text-base));
--text-xl: calc(var(--scale-factor) / (var(--scale-factor) - 2) * var(--text-base));
--text-2xl: calc(var(--scale-factor) / (var(--scale-factor) - 4) * var(--text-base));
}

このように宣言しておくことで、次のように計算されるようになる。

html {
--text-base: 1rem;
--text-sm: calc(7 / (7 + 1) * var(--text-base)); /* 0.875rem */
--text-lg: calc(7 / (7 - 1) * var(--text-base)); /* 1.166rem */
--text-xl: calc(7 / (7 - 2) * var(--text-base)); /* 1.4rem */
--text-2xl: calc(7 / (7 - 4) * var(--text-base)); /* 2.333rem */
}
html {
--text-base: 1rem;
--text-sm: calc(6 / (6 + 1) * var(--text-base)); /* 0.857rem */
--text-lg: calc(6 / (6 - 1) * var(--text-base)); /* 1.2rem */
--text-xl: calc(6 / (6 - 2) * var(--text-base)); /* 1.5rem */
--text-2xl: calc(6 / (6 - 4) * var(--text-base)); /* 3rem */
}

余白のサイズもこれにもとづいたものに設定している。外から見えるところとしてはそんなところ。後は裏側の、僕にしかわからないような変更点がいろいろ。

  • テンプレートエンジンをLiquidからHandlebarsに置き換えた
    • RomeのウェブサイトはEleventy製なんだけど、Liquidが採用されているのを見て、Nunjucksより機能が絞れてて良さそうと思ったけど、いろいろ中途半端だった。気の迷いだった
  • Handlebarsを使うためのフィルターやデータフロー周りの調整
  • YAMLファイルをタブインデントを使って書いてパース時に変換していたけど、4スペースに変えた
    • これもRomeのパクり。普通で良い
  • シンタックスハイライトを実装した
  • 投稿のdescriptionは本文の最初の段落と同じ内容だったけど、同マークダウンファイルのFront Matterにコピペして設定していたので、自動的に本文から読み取るようにした
  • 投稿の並びをファイル名順にしていたけど、publishedフィールドにもとづいて並べるようにした
  • フィードの生成をプラグインのサンプルとして示されているテンプレート(Nunjucks)そのままでやっていたので、一貫性のためにHandlebarsで書き直した
  • データファイルにいろいろ重複したデータがあったので一元化した
  • いくつかのテンプレートで同ファイル内にFront Matterを書いていたけどマークダウンファイル以外では全部外部ファイルに書くようにした
  • 投稿ファイルを変更してGitHubにプッシュしたらGitHub Actionsで自動的に変更日時が書き換えられるようにしていたけど複雑なので廃止
  • Netlify CMSを使えるようにした
  • 404ページを作成
  • フッターの「編集履歴」リンクを投稿の詳細ページ以外では出さないようにした
  • リンク一覧のコンポーネントを<article>と見出しでマークアップしていたけど、単に<ol>/<ul><li>にタイトルは<p>にした
  • アイコンの冗長なIDをシンプルにした
    • icon-chevron-righticon-chevron
    • icon-arrow-backicon-back
  • CSSファイルをインライン化していたけど外部ファイル化した
  • 余白の名前をspace-smとかspace-lgみたいにしてたけど連番に変えた
  • Clusterパターンのmarginの設定が面倒なのでやめて、Flexboxにgapを使うようにした
    • Safariには3月のリリースまで実装されないけど時は早く過ぎるのでオッケーにした
    • 余白はClusterのモディファイア的に実装していたが、これによってgap用の汎用的なユーティリティクラスに分けられるようになった

まだいろいろある気がするけどとりあえずこんなところ。これらのことがかなりうまいやり方で達成できた。そこに満足感がある。

サイトの構造とか見た目はちょっとしか変わってなくて、そこだけ更新しようとすればまあできたんだけど、こういう微妙な負債みたいなものは累積してそのままになりがちなので思い切って全部書き直したりすることがある。声を大にしてはっきりと「これが生産性を下げている」と言えるわけではない微妙なやつがいろいろあるというのがポイントで、あるひとつの問題だけ片付けさえすればすべてがよくなるような状況はあまりない。なんとなくいまいちな設計が全体的に蔓延していて、うまく説明できないけどちょっとずつ一貫性が崩れてるとか、微妙にDRYになってないとか、橋渡し的なコードが多いとか。

すでにある程度できているコードベースを運用していると、あくまでそれを基準にして次に取る手を決めていくことになるので、それなりの理由がない限りは現状維持になるのが自然だ。一方で、一から作るなら全然違う完成形がイメージできるというのも当然あるはずで。現実的には、そう思うたびに都度全部書き直しているとどれだけ時間があっても足りないので、日々費用対効果みたいなものを意識しながら気持ちに折り合いをつけていくしかない。しかしことこのような個人的かつ小さいプロジェクトについては、むしろ積極的に全部書き直すようにしている。

「あくまで僕の場合は」と言っておくけど、一から書くという気になっていないと最善のコードは書けない。すでにある程度のコードを積み上げてしまっている限り、それを利用した上で次の手を選択するという狭い範囲の中で発想が無意識に制限されてしまう。「その状況においては」良い選択ができるかもしれないけど、制限が外れてしまえば第三者的には妥協の産物になる。

書き直すということは一度書いてしまってある程度わかっているものをもう一度書くということで、作る対象に対しての理解度がかなり上がっている状態からのスタートを意味する。やらないといけない仕事や起き得る問題は把握できていて、場当たり的な措置を取らざるを得なかった箇所も覚えている。一度書き終えることではじめて全体的に見渡せるようになって、本当にあるべきだった形がやっとわかってくる。人生は2周できないが設計は2周できる。

そしてこの2周目の経験というのは普段なかなか得難いものだと言える。全部書き直す機会はそうそうない。作ることのフィードバックとして受けた痛みに対して、小手先の対応でお茶を濁すのではなくて、根本的にどうすればこのような問題が起こらないのかを考えた上で、実証することがこのフェーズではできる。全部書き直すとまではいかなくとも、日々の1コミットの裏で積み重ねられる検証や意思決定の数々は紛れもなく設計の結果だろうが、これはまた焦点が別のところにある。真に全体を見るというのは究極的にはやはり全部書き直すことだと思う。

またそのプロジェクトだけの経験に限らず、新たにどこか別の場所で得た知見やコミュニティの中で共有されたものなんかもあるだろう。当時は満足していたコードが、久しぶりに見たらもう酷くダメな出来に見えることもある。そうなるだけの時間を経てきた今の自分が持てる知識のすべてを統合して全部書き直したとき、再構成された設計は見違えるようになるのはもとより、それを経た自分もまた変わっている。

コードの一貫性を壊すのは妥協だが、妥協せざるを得ない状況を作るのは設計である。つねに完全さを目指していれば選択のブレはなくなるが、既存の仕組みとうまく整合性が取れずにハマらない瞬間はどうしてもある。しかしそうなってしまう場面を減らすことはできる。

いつも全部書き直すことはできない。でもその経験のおかげで、新たに作るものであっても、部分的には書き直しの洗礼を受けた完成度に最初から到達できる。書き直しの経験はその場限りのものではなく、さまざまな解釈の可能性を将来に残してくれる。