アドカレのブログでアドカレ作った話を書くのはさすがにちょっとメタすぎる気もするが、学ぶことは少なくなかったのでまとめる。思いの外スムーズにいったこともあって、小規模ながらもおもしろかった。
課題提起
自発的に何かを作る、数少ないきっかけの一つはやっぱり自分のかゆいところをかきたい、自分で感じるニーズに答えること(他にもいろいろありえるけど)。今回は何がそうだったのかというと、このClojureアドカレ含め、アドカレの約束(もしくは参加したいアドカレ)が多くて、一箇所で管理したかった。Qiitaのアドカレはそれはそれでいいんだけど、テーマが決まっていて、複数のカレンダーに参加する場合それをまとめて管理したい。Qiita上で自分だけのアドカレ作ることはもちろんできるが、この時期ならいっそ自分で作ってみたいと思った。
使った技術
人に共有するのは二の次で、自分だけで管理したい思いがきっかけなので、そもそもサーバーはいらないと判断した。フロントだけで、ブラウザのLocalStorageとかを使えばやりたいことは実現できる。でもそのフロント用のブツは配信する必要はあるので、静的コンテンツとしてそれを自分のクラスターに入れようと思った。なので技術スタックとしては以下の通り
- shadow-cljs (ClojureScript)
- shadow-css (ClojureScriptでCSS書く)
- Github Actions (イメージを作ってデプロイ)
- Kubernetes (実行環境)
試したこと
CLJSでアトミック
Clojureならアトム(atom
)とは馴染みはあるかもしれないが、これはフロント界隈で人気そうな思想の方のアトミックデザインの方。何かというと、UIの要素(コンポーネント)を法則に沿って分割して、いい感じに置き場と組み合わせ方が決まるというのが魅力。
今回は1ページだけの小規模なものなのであまり徹底して出番があるわけでもないが、一方でカレンダーなので十分にコンポーネントの再利用性を発揮できるところでもある。カレンダーは行があってカラムもあって、一日いちにちの「枠」も最低限12月分で31個はあるのでそれはきれいに書きたい。
ClojureScript自体もそうではあるが、reagent/re-frameはものすごく強力なツールで、すごく気持ちがよくサクサクと開発が進む。アトミックデザインと混ざるとなおステート管理などややこしいことの方針が決まっているので悩むことはそう多くない。
今回ではアトミック階層を使い切ってみせることはさすがに困難な規模だったが、個人的に「どうしよう」の基準はある程度定まった:
- 1つのファイルで行数が増えすぎると何か切り出した方がわかりやすい
- 再利用性がある部位は切り出す(例えば
mapv
とかで数多く作るもの、今回では一日) - ロジックが「そこだけ」でかなり詰まったところ(今回でいうとダイアログ)
- 同じCSSクラスを使うエレメント郡(今回でいうとダイアログの入力フィールド;未分割)
shadow-css
shadow-cljsは今どきCLJSの標準環境になっている(leinを思わせるほど)のでかなり知られていると思うが、同じ作者の関連してCSSをCLJSの文法で書くライブラリ、shadow-cssはあまり知られていない。正直知られても、あまりユーザーフレンドリーではないので(これもまた開発者本人が自分自身の課題を解決するために作られたもので)ちょっと頑張る前提でかからないと動かせることすら難しいからまだ厳しいかも。
一方でその「ちょっと頑張る」を嫌がらなければめっちゃくちゃスムーズな開発体験は確保できる。その頑張るところは例えば
以前は手でCSS書く者だったので、すごく助かってる気がした。もちろん他にもCLJSでCSS書くライブラリがあるが、全般的にマクロが主役(defstyle
とかからのマクロ雪崩)であまり好きじゃなかった。一方でshadow-cssの css
マクロ(マクロには変わりないけど)は静的な実装で、他のマクロ沼と比べてのブラックボックス感は薄く個人的にしっくりきた。
Github Actionsでリリース
すでに7大陸最高峰サイトでは自動リリースしているが、今回はコミットよりGithub上でリリース作る時のタグを活かしたかった。環境もJekyllとClojureScriptのビルドで大きく違っているので、思ったよりずっと苦戦した。
Actionsのenvironmentは便利だと感じながらも、最終的に罠と感じたところは
- tagのpushで起動したワークフローだとコミットを追加するにはまずブランチに切り替える必要がある
- コマンドラインのgitのクセは知らないから非常にめんどくさい
- bashもなかなかめんどくさい(特にこうしてCI/CDで1コミット1コミットでデバグする時)