アペフチ

風邪で寝込みながらfukabori.fm聴いていた

風邪で寝込みながらポッドキャストを聞いていた。熱が出ると画面見るの辛いし、端末を持ち続けるのも辛いので音声メディアはとてもいい。

23. 社内ISUCON w/ yosuke_furukawa | Fukabori.fm

@yosuke_furukawaさんと、社内ISUCONの話。

ベンチマーカーを作るのに、オープンソースのk6Postmanを元にして作っている、と言っていて、「これぞエンジニアリング!」と興奮した(けどこれは別にエンジニアリングかどうかは関係ない。どういう言葉を僕は本当は使いたかったんだろう?)。

13. ペアプロやテストの疑問とか、ソフトウェアエンジニアの育成とか | Fukabori.fm

twadaさんと、ペアプロやテストの話。

ペアプロをベテラン×ベテランの組み合わせでやる時のメリットの話が、自分で実際やらずには考えられない内容だったのでためになった。アーキテクチャーみたいな部分での決定について、ペアプロでやっていると共犯関係を作れるとか、自分にない観点での議論ができるとか。なるほどなあ。

あと、ペアプロやってると、「他人に見られるというただそれだけで雑なコードを書かなくなる」「これはコードレビューも同じ」みたいな話も納得感あった。

15. 良い組織とは何か?どのように良い組織を作っていくのか? | Fukabori.fm

とてもいい話だった。クレブスサイクルというのを知れたのが僕には大きい。

14. なぜ、エンタープライズ業界でアジャイル・リーンは普及しないのか? | Fukabori.fm

hiranabeさんと、アジャイルとかの話。

何か事業やプロジェクトが失敗した際に、「企画はよかったのだが、実施がうまくいかなかったのか」「それとも企画がそもそもよくなかったのか」という振り返り方をするのだけど、それはよくないよ、という話がのっけから行われていて、引き込まれた。

Voicyをポッドキャストアプリで聴きたい

風邪の時とかそうでなくても寝ながらポッドキャスト聴くのはとても好き。

最近聴いて面白かった音声メディアに塩谷舞さんのVoicy「塩谷舞の東京とNYと大阪と。」があるのだけど、これも自分の好きなポッドキャストアプリでサブスクライブして、他のポッドキャストと同じ場所に並んで、ポッドキャストのように聴けたらいいのになあと思う。

雑多にプログラミング、集中力の衰え

OgaのXPathの名前空間サポートの拡充

EPUB ParserというRubyGemを作っている。電子書籍用に使われるEPUBというファイルフォーマットを扱うライブラリーなのだけど、EPUBというのは雑に言って「XHTMLとCSSと画像とメタデータ用XMLファイルをZIPアーカイブした物」なので、内部でXMLを扱う必要がある。

XMLライブラリーは切り替え可能にしていて、今はRuby標準添付のREXMLの他にNokogiriをサポートしている。これに加えてOgaもサポートしたいなあと前々から思っていた。

最近、全然プログラミングを楽しむ時間が取れていなくてあまりにフラストレーションが溜まってしまったので、他にやることもあったのだけど、Ogaに取り組むことにしてしまった。具体的には、Ogaの方のImprove XPath namespace supportというイシューを解決しようというものだ。これができれば、EPUB Parserの方にOgaサポートを追加するのは簡単。

問題の特定や変更箇所は既にイシューページで議論されているので、後残っているのはOgaの構造を理解すること、それから、実際に手を動かしてパッチを書くことだ。ソースコードを眺めたり動かしてみたりしてYorick Peterseさんの提案するAPIを定義することはできたので、後はAPI経由で渡された名前空間エイリアスを使うところを実装すればいい、というところまで進んだ(未コミット)。

Fiddleでlibzip

EPUBというのは「XHTMLとCSSと画像とメタデータ用XMLファイルをZIPアーカイブした物」なので、EPUB ParserではZIPアーカイブを扱う必要がある。これも切り替え可能にしていて、ピュアRubyのArchive::ZipとCのlibzipのバインディングであるZip/Rubyをサポートしている。当然Zip/Rubyの方が速い。のだけど、長いこと開発が止まっているので、何とかしたいなあと思っていた。具体的には、自分でメンテナンスを引き継ぐか、別のlibzipバインディングを作るか、(Rustに興味あるので)RustのZIPクレートをRubyから使えるようにしてみるか(Rutieなどで)。

それとは別にRubyでFFIする時にRuby FFIばっかりが使われてFiddleが見向きもされないのが何だかなあと思っていたので、二番目の「別のlibzipバインディングを作る」をFiddleを使ってやってみようと思った。

とは言え、Cプログラミングが全くの初心者なので、ドキュメント読んだり何とかlibzipのAPIリファレンス見たりしてやってみてるのだけどうまくできてるのか自信がない。特にメモリー管理が適切なのか全然分からん。途中経過がこんな感じ。どうなんでしょう?

require "fiddle/import"

module Libzip
  CREATE = 1
  EXCL = 2
  CHECKCONS = 4
  TRUNCATE = 8
  RDONLY = 16

  module FL
    NOCASE = 1
    NODIR = 2
    COMPRESSED = 4
    UNCHANGED = 8
    RECOMPRESS = 16
    ENCRYPTED = 32
    ENC_GUESS = 0
    ENC_RAW = 64
    ENC_STRICT = 128
    LOCAL = 256
    CENTRAL = 512

    ENC_UTF_8 = 2048
    ENC_CP437 = 4096
    OVERWRITE = 8192
  end

  extend Fiddle::Importer
  dlload "libzip.so", "libzip.so.4"

  typealias "zip_flags_t", "uint64_t"
  typealias "zip_uint16_t", "uint64_t"
  typealias "zip_uint32_t", "uint64_t"
  typealias "zip_uint64_t", "uint64_t"
  typealias "zip_int64_t", "zip_uint64_t"

  extern "zip_t * zip_open(const char *path, int flags, int *errorp)"
  extern "int zip_close(zip_t *archive)"
  extern "zip_int64_t zip_get_num_entries(zip_t *archive, zip_flags_t flags)"
  extern "zip_file_t * zip_fopen_index(zip_t *archive, zip_uint64_t index, zip_flags_t flags)"
  extern "int zip_fclose(zip_file_t *file)"
  extern "void zip_stat_init(zip_stat_t *sb)"
  extern "int zip_stat_index(zip_t *archive, zip_uint64_t index, zip_flags_t flags, zip_stat_t *sb)"

  Stat = struct([
                  "zip_uint64_t valid",
                  "const char *name",
                  "zip_uint64_t index",
                  "zip_uint64_t size",
                  "zip_uint64_t comp_size",
                  # "time_t mtime",
                  "zip_uint32_t crc",
                  "zip_uint16_t comp_method",
                  "zip_uint16_t encryption_method",
                  "zip_uint32_t flags",
                ])
  class Stat
    NAME = 0x0001
    INDEX = 0x0002
    SIZE = 0x0004
    COMP_SIZE = 0x0008
    MTIME = 0x0010
    CRC = 0x0020
    COMP_METHOD = 0x0040
    ENCRYPTION_METHOD = 0x0080
    FLAGS = 0x0100
  end
end

errorp = 0
archive = Libzip.zip_open("book.zip", Libzip::RDONLY, errorp)
pp archive
pp num_entries = Libzip.zip_get_num_entries(archive, Libzip::FL::UNCHANGED)
0.upto num_entries - 1 do |index|
  file = Libzip.zip_fopen_index(archive, index, 0)
  stat = Libzip::Stat.malloc
  Libzip.zip_stat_init stat
  p Libzip.zip_stat_index(archive, index, Libzip::Stat::NAME|Libzip::Stat::SIZE, stat)
  p [index, file, stat.size, stat.name.to_s]
  p Libzip.zip_fclose(file)
end
pp Libzip.zip_close(archive)
pp archive
# pp Libzip.zip_close(archive) # => SEGV

FiddleはRuby標準添付のFFIライブラリーなので、追加gemをインストールする必要がない。おまけにWindowsでも動く。ので基本はこちらがいいんではないかなあ。内部ではFiddleを使いつつ、APIだけRuby FFIと同じにするためのFiddleyというgemもあるので、興味ある人はこれを使って移行を始めてもいいだろう。

Public Outbox

自分のトゥートとかブログポストとかのActivityPubのアクティビティを一か所に集めて、「他人がここを見れば自分のアクティビティが分かる」というようにできたらどうだろう、と考えたりしてた。ActivityPubのoutboxのうちパブリックな物のリスト、とも考えられるので、Public Outboxという名前はどうか。というようなことを考えたりしていた。何で作るのがいいんだろう。Rails?

因みに名前はpublic-inboxのもじり。

集中力の衰え

以前だったら、OgaのXPath名前空間拡充は、ここで手を止めずにもっと進めていたと思うのだけど、今はそれができなくなってしまっている。歳なのかなんなのか、集中力が衰えてしまっているなあと感じる。まずいまずい。

WordPressでGutenbergのブロック追加ができない

ここの「+」の所。

ce78a14fa17a3743411af09f8bf3b57c

これが何故かグレーアウトされたままでブロックが追加できなかった。
「Gutenberg cannot add block」とかでググったら出てくる解決法の、「プロフィール画面で『 ビジュアルリッチエディターを使用しない』のチェックを外す」をしてもだめ。

なんでだろう思いつつ、「Classic Editor」プラグインを入れてみたら、TinyMCEになるわけだけど、なんかHTMLしか入力を受け付けない、WYSIWYGモードにならない。ここで「WordPress wysiwyg not shown」とかでググったら、「WordPressはUAを見てリッチエディターの有効・無効を判定しているので、CloudFrontを使っているとリッチエディターが使えない」ということが分かる(例:Rich Text/Visual/WYSIWYG Editor does not work in WordPress behind cloudfront – dtbaker.net)。
リンク先では functions.php を編集しているけど、CloudFrontでUser-Agentヘッダーをフォワードするように設定して解決。

Gutenberg関連だという思い込みがあって中々解決に至らなかった。CloudFrontは盲点だったなあ。
もうソースコード読むしかないか……という気持ちだったので、そうなってたらまあ、発見できたかも知れないが相当時間か掛かりう。「Classic Editor」を入れる、というのを試して本当によかった。