| @技術/プログラミング

7 年間眠っていたブランチを起こして、 Lokka の ActiveRecord 化に取り組み始めた。元のブランチは hrysd さんが取り組んでいたやつだ。

現在の master の内容を取り込むのが大変だった。 active-record ブランチでは ActiveRecord 化と同時に様々な改良・改変が行われていて、 master の内容と思い切りコンフリクトするものがあったりして、コンフリクトの解消作業はかなり大変だった。

active-record の大きな変更点は以下。

  1. カスタムパーマリンク機能の削除
  2. 「もっと読む」機能の削除
  3. カテゴリーをネストさせる機能の削除
  4. ユーザー認証方法の変更(カラムの追加)

このうち 1 と 2 は削除された機能を復活させた。自分が使っていてなくなると困るし、特にカスタムパーマリンクは既存サイトでこの機能を使っているところがデッドリンクだらけになって散々な目に遭ってしまう。 4 に関しても、 master の認証方法と互換性を持たせないと既存ユーザーがログインできなくなるので古い認証方法でもログインできるようにした。

3 に関しては WordPress との互換性を考えると必要かもしれないが、自分で使ってなくてユースケースが思い浮かばないのでいらないかなという感じがする。そもそも Lokka は WordPress キラーとなるべく Fjord 社内で作られ始めたと認識しているが、 WordPress は相変わらず元気だし Lokka の利用状況的にも WordPress alternative を目指す必要はないと思う。

そのほか、 rake db:delete が動かなかったのを直したり bundle update をしてぶっ壊れたところを直したり、デフォルト以外のテーマが ActiveRecord 化してなかったのを対応させたり( dm-pagination から kaminari へ移行)して ActiveRecord 5 で概ね動くところまで持ってくることができた。

ActiveRecord は良くできていて、 DataMapper だと難しかった JOIN した上での集計クエリなどが書きやすい。ドキュメントが山ほどあるのもよい。 DataMapper は情報が少ないのが一番つらかった。一方で DataMapper だと気にする必要がなかった N+1 問題を自分で解決する必要がある。 View でうかつに参照するテーブルのデータを増やすと N+1 問題が発生して途端にパフォーマンスが劣化する。

また、誰がどんな DB で利用するかわからない状況で db/schema.rb を git で追跡してよいものかというのもひかっかる。 ActiveRecord を使う以上、 migration と schema.rb からは逃げられないのだが、 MySQL で使う人も PostgreSQL で使う人も SQLite で使う人もいて、それぞれの DB でマイグレーションを実行するごとに異なる schema.rb が吐き出されるので git で追跡すべきではないのではないかと思う。どんなデータベースで利用されるかを意識せずに開発できる、という点では DataMapper の方が CMS 開発向きだったと思う。

以前の Lokka であればあまり Ruby 知らない人でもとりあえず git clone して自分の好みのテーマを追加して Heroku に push すれば動かせたが、 ActiveRecord 化することで N+1 問題など Rails に強くないと触りにくい感じになってしまった。ただ、 Sass は Ruby を捨てて C に移行したし、 Slim なんかも JavaScript フロントエンド技術の盛り上がりの陰で開発は停滞している。こういう時勢になってくるとフロントエンドに強いマークアップエンジニア兼ウェブデザイナー的な人が Ruby 製の CMS を使う動機はなくなってしまう。 CMS を使ったサイト構築でも Sass や Slim を使って HTML コーディングの生産性を上げ、 Heroku を使って簡単に deploy できる、というのが komagata さん達が最初に想定してた Lokka のユースケースだと思うけど、 JavaScript によるフロントエンド技術が強力になりすぎて、生産性の高いフロントサイド開発のために Ruby を経由する必要がなくなってしまった。


これから Lokka はどうあるべきなのだろうか。モダンなフロントエンドフレームワークは強力だ。否が応でも JAMStack に対応していくしかないだろうと思う。つまり Sinatra で作るのは API (と管理画面)だけになり、フロントエンドは React や Vue.js で作るべきだろう。ちょっとしたサイトを JAMStack で構築したいが、 API に良いのがない、とはいえ Rails は使いたくない、というケースで Lokka を使うという感じだろうか。ただ、いまは Firebase なんかもあるのでそもそも API を自前で持つ必要はないのかもしれない。どのみちかなりニッチなユースケースになるだろう。

ちなみにこのブログの Archive ページは中途半端ながら React で作っていて割といい感じに動いている。 ActiveRecord 化が済んだら React でサイト全体を作り直してみたい。

| @技術/プログラミング

DataMapper のドキュメントを見たくてググったが出てくるのは Stack Overflow ばかりで公式サイトが検索結果に出てこない。 GitHub の DataMapper のリポジトリ( Archive されている)経由で見に行ってみると、なんと ROM ( Ruby Object Mapper ) のページにリダイレクトされた。

ROM は Hanami で使われる ORM で、 DataMapper よりもさらに ActiveRecord と使い心地が異なる。

Qiita の以下の記事を読むと使い方のイメージが湧く。

軽くてシンプルなのだろうがだいぶ特殊だ。

Lokka の使い手は少なくとも Heroku が使える人で、そういう人ならば ActiveRecord の方が Rails の本やドキュメントで学びやすいはずだ。というわけで早めに、真剣に ActiveRecord への移行を考えなければならない。

| @技術/プログラミング

2019-08-24 06.57.38.gif
2019-08-24 06.57.38.gif

Lokka のプレビューはサーバーサイドに保存時と同じパラメーターを POST して、 DB にレコードを保存せずレンダリングだけ行うが、 GitHub や Kibela のようなタブ切り替えでインスタントに Markdown のプレビューができると便利だろうと思って、 Markdown で編集中に Edit と Preview をタブっぽい UI で切り替えられるようにしてみた。

Markdown のレンダリング自体はサーバーサイドで行っているので、プレビューしたときと実際に保存したときで Markdown の解釈が異なるということもない。

ただリモートで生成した HTML 文字列を DOM に挿入するときに単純に document.innerHTML = body; のようなやり方をしてしまうと JavaScript が動かず困ったので、 iframe を作って document.open(); document.write(body); document.close(); するやり方をとった。そうなると今度は iframe の高さを body のレンダリング終了後に調整する必要があって色々面倒だった。たまに高さがずれたりはするが、基本的にはめっちゃ便利。

Lokka の利用者少ないと思いますが、 Lokka 本体にも入れようと思います。 Ruby の最新版への追従へも最近は行えてないのでこれもやります。

| @技術/プログラミング

このブログの記事投稿画面で、画像をコピーアンドペーストでアップロードできるようにした。以前、ドラッグアンドドロップではアップロードできるようにしていたが、 GitHub や Kibela ではコピーアンドペーストでアップロードできるようになっておりはちゃめちゃに便利だったので真似してみた。こんな感じ。

2019-08-18 15.31.56.gif
2019-08-18 15.31.56.gif

ハイパー便利。

Reference

| @技術/プログラミング

Lokka の wysiwyg エディターは jQuery ベースの jwysiwyg といつやつが採用されている。

しかしここ最近はメンテナンスされてなくて、最近の Chrome では利用できない状況だったりする。以前、ファイルアップロード機能を付けたときも jwysiwyg の不具合が原因で wysiwyg モードでの画像アップロードは断念した。

最近のモダンな wysiwyg はどんなのがあるんだろうと調べてみたら Quill ってのが GitHub で 18000 くらいスター付いてて良さそうだった。

ちょっと試してみたところ wysiwyg で画像のアップロードもできるようになったので jwysiwyg からこいつに置き換えるのも悪くはなさそう。

ただ Quill は擬似 textarea なので実際の form には対応していない。 SPA で利用されることが想定されており、 Ajax 前提なつくりとなっている。サーバーサイドで HTML をレンダリングする昔ながらのウェブアプリで使うには一手間必要そうだった( form の onsubmit で texarea を createElement して Quill で入力したデータをぶっこむなど)。

追記

Pull Request 出した。

さらに追記

↑の Pull Request 、 Merge されたんで Lokka の wysiwyg エディターは Quill となりました。

| @ブログ

Facebook にウェブサイトの URL をはっつけるとき参照される HTML メタ情報の仕組みに Open Graph Protocol ってのがある。 Facebook に URL を貼ると bot が URL の内容を読みに行ってページの概要や画像を取得し Facebook 内に埋め込み表示するというもの。 Facebook を見ている人はリンク先の内容をクリックする前に概要を把握できるので、リンクをクリックして見たい情報じゃなかった、ということを避けられる。 Facebook が考案して策定した仕組みだけど、 Facebook に限らずいろんなサイトで OGP タグを出力してるし読み込んでる。 Twitter にも似た仕組みあって Twitter Card という。この辺の対応は結構前にやってた。

ただ自分のサイトが OGP タグを提供するだけではつまんないなと思ったので自分のブログにペロッと URL を貼ったときに相手先に OGP タグがあればそれを出力するようにしてみた。こんな感じ。

OGP Preview
OGP Preview

しかしここで困ったことがあって、↑でリンクしてる Circle のサイトは HTTPS で配信されておらず、単純に Circle のサイトで og:image に指定されている画像を SSL 化されているこのブログで読み込むと Mixed Content になってしまう。せっかく HTTP/2 で配信していたのに台なしになってしまう。またそもそも og:image は Facebook でシャアされることを想定されていることがほとんどなので、画像サイズがデカすぎていい感じにスクエアに表示するためには CSS の小技を駆使したりする必要があった。

いい感じに解決する方法ないかなと調べていたら良いのが見つかった。

Go で書かれた Image Proxy Server で、 HTTPS Proxy は当然のこと動的リサイズもできる。使い方は簡単でバイナリを落としてきて動かすだけ。 Go なんで ImageMagick をどうしたりとかを考えなくて良い。 そもそも Docker イメージも提供されているので Docker をインストール済みなら docker run するだけでも動く。 めっちゃお手軽。

こいつのおかげで HTTPS で配信されていないサイトの OGP タグを読み込んでも Mixed Content にならずに済むようになった。また og:image は適切にリサイズできるようになった。画像変換サーバーとかは結構難しいやつで個人のブログでこんなに簡単に使えるものだとは思ってなかったので正直ビックリした。

AWS の登場で大企業じゃなくても CDN 使ったり仮想サーバーでウェブシステムを構築したりできるようになった。さらには Go や Docker といった技術のおかげで複数の込み入ったソフトウェアを組み合わせて構築していく必要があったシステムが、まるで jQuery を使うような感覚でポン付けで使える時代になってきている。とても素晴らしい。

ちなみに OGP の取得には open_graph_reader という gem を使っている(昔からある opengraph という gem はメンテナンスされておらず最近の Nokogiri で動かない)。 open_graph_reader の作者が結構 Opinionated な人で、以下のような Anti-featurs を掲げている。

open_graph_reader Anti-features
open_graph_reader Anti-features

http://ogp.me/ の仕様に準拠していないサイトのことは完全無視というつくり。個人的にはこういう思想は好みだが、現実問題として使い勝手が悪い。例えば hitode909 さんのブログの OGP タグを取得しようとしたところ以下のようなエラーを出して取ってくれなかった。

スクリーンショット 2018-05-26 10.08.47.png
スクリーンショット 2018-05-26 10.08.47.png

article:published_time は ISO8601 形式の datetime であるべき、とのこと。はてなブログはかなりシェアが大きくリンクする機会が多いので残念。

| @技術/プログラミング

lokka/lokka 、 Pull Request を出す度に Hound CI のチェックが走って bot にコードレビューでぼこぼこにされるので、この bot を黙らせるべくガチャガチャやってた。 Hound CI のチェックルールは Rubocop に準拠しているようで、 2011 年からある Rack アプリを Rubocop のチェックにかけるのは面白かった。

Lokka 、意外と Hacky なコードが多く、条件式内での代入とか、ヨーダ記法とか、後置の until とか、スコープが広い一文字変数とか、めっちゃ長いメソッドとか、 if 文のネスト、代入したものの使われてない変数なんかを修正した。 method_missing はカスタムフィールドを定義できるという Lokka の仕様上根絶できなかったけど、 .rubocop.yml に最低限の除外ルールを追加して Rubocop のチェックはパスするようにできた。

Lokka 、 ORM が ActiveRecord じゃないことが問題だと思ってたけど、真の問題は lib/lokka/helpers/{helers,render_helper}.rb にビジネスロジックが詰め込まれてることだと思った。しかもこのあたりのコードの可読性がよくなく、触るのが怖い感じの複雑なやつが多い。この辺のコードをもうちょいクラス化して分割し、ユニットテストも手厚くしていかないと ORM を変えても F/E を今風にしてもウェブアプリケーションとして生存していくことは厳しいと思う。

前に進んでいくためにも Rubocop のチェックを入れる&パスさせるのはプラスになると思う。 頑張ってメンテしていくぞ。

追記

この辺のコードをもうちょいクラス化して分割し

と書いたけど、 Rails と違って手軽にサクッと作れるのが Sinatra の良い所なわけではあって、仕事で作る Rails アプリのノリでクラスやファイルを分割したりするのは違うのかもしれないと思った。 Rails で作られたオープソースの CMS やブログツールに長生きし続けるものがないのも、 Rails の場合、個人が偶発的に始めてメンテ出来るようなものになりにくいからかも知れない。

とはいえヘルパーがビジネスロジックを所持しているのはテスタビリティやメンテナビリティが良くないので Lokka と心中する覚悟でやっていくぞ!!!、!