ログ日記

作業ログと日記とメモ

「わかる」と「読める」と理解する

圏論の本を読んでいてよく詰まるのが、数学記号が読めないということ。
数学記号の表 - Wikipedia
色々あるけど、どうやって読むんだろうか。
それとも数学の人は読んでないのかな?


例えば「192.168」と書いてあれば「イチキューニーイチロクハチ」と読む。「ヒャクキュージューニーテンヒャクロクジューハチ」とは読まない。
「192.168.0.0/24」と書いてあれば…これは読めない。192.168.0 のネットワークね、と頭の中で考える。「スラッシュニーヨン」とは読まない。読むとしたらどちらかというと「ニーヨン」じゃなくて「ニジューヨン」だ。
「192.168.0.0/28」と書いていれば…IP 16個ね、と考える。読まない。「192.168.0.0/27」と書いていれば…ちょっと考えたり数えたりする。/27 には慣れていない。

$item->name と書いていれば、「アイテム、ネーム」と(頭の中で)読む。「アロー演算子」という呼び方は知っているけれど、「アロー」は読まない。

heightは誰かに喋るときは「ハイト」だけれど、頭の中では「ヘイト」と読んでるっぽい。width は読んでない。喋る必要があるときは「幅」って言ってる。
column は明らかに「カラム」だけど、頭の中では「コラムン」と言ってる気がする。


音として読めなくても、理解できるし使えるし、日常的に使っているのに読みづらいということが起こっている。



数学の式なんかの場合はどうなっているんだろうか?
例えば
写像の合成 - Wikipedia
ここにある式が読めなくて、読めないからそこで文章を読む流れが詰まる。
・とか○とか矢印とか色々あるし、xもXもある。筆記体とかギリシャ文字とかもある。
でも、もしかして読む必要はないのかな?
どういう手順で音として読まずに理解するのか、上の192.168/24とかの例は自分のことなのにあまり分かってないな。



「192.168.0.0/27」は理解していると言えるけれども、見て「わかる」という感覚までにはなっていない。
「192.168.0.0/24」は感覚的にわかるレベルになっている。「下位8ビットのアドレス空間」「クラスC」「255.255.255.0」などがぼんやり思い浮かぶ。
もし「192.168.0.0/13」とか書かれていたら何も想像できないので、紙に書くようなことをしないと頭に入ってこないし、そのときは覚えてもたぶんすぐ忘れる。


つまり…どうすれば良いかというと、結局数をこなして慣れるしか無いということかな。


他には、ギターを習っていたけれどピアノは習っていないので、ト音記号は読めるけれどもヘ音記号は読めない。
しかも、読むより指で押さえる方が簡単ということが起こる。
たぶん読んでない。眺めているという感じかもしれない。

そういえばアルファベットの綴りが分からないときは、エアータイピングでキーボードを打つようにして綴りを思い出すことがある。「application」「transaction」「conversion」「extension」などは、指でタイプする方が早くて正確に思い出せる。手書きだとちょっと不安がある。
これもアルファベットの文字としては読んでないし書くことも無いけれど、タイピングは何度もしているからだ。


これをふまえて、数学記号に当てはめるとどうなんだろう?
やっぱりノートに書くような何らかの出力が必要な気がする。
練習問題的な、数をこなさないといけないのかもしれない。

ちなみに、昔はピアノで5曲ぐらい弾けたんだけど、今は弾けなくなったし楽譜を見ても弾けなくなってしまった。
たぶん基礎練をせずに曲だけ練習したからだ。
ヘ音記号を数えて読んだり、一音一音確かめながら弾いたら一応少しずつは進むんだけれど、わかるレベルまでいってない。
理解はしているからゆっくりやれば出来るけれども、音楽の場合はゆっくり理解していては曲にならない。

コンピューターに関しても、もし大学に行ってなかったらプログラムだけ書いて基礎的でCS的なことはやらなかったに違いない。
なかなか難しいものだね。


数の話だと、7 + 6 は 13 だけれども、これはどうやって導き出しているのか。
たぶん暗記している。数で暗記してるんじゃなくて、イメージで暗記してる。なんか6が7に引っかかってぽろっと3と3に分かれるイメージ。7は分かれない。10から引いたりもしていない。かけ算の九九のように覚えているわけでもない。
そういうこと?(どういうこと?)

圏論入門 Haskellで計算する具体例から 読んでる

やっと15ページまで読んだ。
1ヶ月前に買ったのに全然進んでいない。
267ページまである。
先は長い。

www.amazon.co.jp

Amazonのレビューは良くないみたい。
でも数学の基礎が無い自分は読みやすい。今のところ、と言ってもたった15ページだけど、暗黙の了解が少ないように見える。
(これがオブジェクト指向が分からない人が読みやすい「オブジェクト指向入門」とかだったら、レビューが低いのは分かる気がする)
こういう初心者向けの本じゃなくて数学書籍の棚にある教科書っぽい本だと、最初の1ページに書いてあることが本当に分からない。分からなさすぎて新鮮で笑ってしまうくらい分からない。単語が100個でてきたら90個は分からないんじゃないだろうか、ってぐらい。
圏論入門 Haskellで計算する具体例から は、まだなんとなく読めそうな感じがある。

この本の前は圏論の歩き方を読んでた。

www.amazon.co.jp

今回は、ノートに分からないことをメモしつつ調べながら読んでみてる。
まったく知らない分野の文章を読んでいると、知らない単語を調べて、その説明に出てくる知らない単語を調べて、ということの繰り返しで、本文がまったく進まないことが起こる。
「群」って何?って調べて、説明に出てくる「自己同型」って何?って調べて、その説明に出てくる「同型写像」って何?って調べて、その説明に出てくる「自己同型写像」とか「始域」とか出てきて、なんかトートロジーしている。

基礎をやらずに進んでるのが問題なんだけど、まあ基礎にはあまり興味が出ないので仕方が無い。
しりとりの圏とかアミダの圏(画像が出てない)とかの例示ができるのなら、別に数学の基礎を知らなくても圏論は理解できるはずだよね、と思って読んでる。

それで、調べた単語や概念の意味を書いて単語帳みたいなものを作りながら読んでいったら、調べ物がループせずにすむかなと思ってノート書いてる。

全然進まなくて続くか分からないけど、今はそんな感じ。

Debian の Let's Encrypt (certbot) を --preferred-chain オプション対応済みのバージョンにしてDST Root CA X3を指定する

2020年9月末でAndroid 7.1以下でSSLが使えなくなるらしいので。
以下はDebian 10 Busterの環境だけれども、stretchでもCentOSでも内容はほとんど同じはず。

songmu.jp
community.letsencrypt.org

バージョン 1.6.0から --preferred-chain オプションで有効期限を一年延ばせる。

# certbot --version
certbot 0.31.0

ただしパッケージで入れているとかなり古いバージョンのはず。

Satoshi Kojima: "そしてsudo certbot --preferred-chain "DST Root CA X3…" - sandbox : skoji


certbot.eff.org

ソースから入れてもいいけど、依存関係で詰まったら嫌なのでsnapdというパッケージ管理ツールを使って最新版をインストールする。
念のため /etc/letsencrypt をコピー退避。

apt install snapd
apt remove certbot python3-certbot-dns-sakuracloud
apt autoremove

python3-certbot-dns-sakuracloud の箇所は、関連パッケージを入れているものに合わせてremove。
systemctl list-timers は消えたけど /etc/cron.d/certbot は残っている模様。
remove --purge していないので /etc/letsencrypt も残っている。

本家certbotマニュアルにしたがってsnapでcertbotをインストールする。

snap install --classic certbot

/etc/profile.d/apps-bin-path.sh にPATHが設定されているので、ログインし直す。

# certbot --version
jq: error (at <stdin>:0): Cannot iterate over null (null)

うーん。。。
snapのcoreを入れる必要があるみたい。
Issues running certbot command - Help - Let's Encrypt Community Support

snap install core && snap refresh core
# certbot --version
certbot 1.8.0

OK。core20とcoreは別物なのね。

古い設定が生きているか確認する。

certbot certificates

新しい設定 --preferred-chain を試したいところだけど、いくつかあるドメインのうち、更新が間近でないものは設定ファイルだけ変更したい。
community.letsencrypt.org
でも無理なようだ。ミスった場合に気付かないからだとか。

実行したらdnsパッケージを入れるのを忘れていたことに気付いた。

snap search certbot
snap info certbot-dns-sakuracloud
snap install --beta certbot-dns-sakuracloud

エラーが出た。

error: cannot perform the following tasks:
- Run hook prepare-plug-plugin of snap "certbot" (run hook "prepare-plug-plugin": 
-----
Only connect this interface if you trust the plugin author to have root on the system
Run `snap set certbot trust-plugin-with-root=ok` to acknowledge this and then run this command again to perform the connection
-----)
snap set certbot trust-plugin-with-root=ok
snap install --beta certbot-dns-sakuracloud

classicは要らない?snapの仕組みが分からないな…。

certbot renew --dry-run --force-renew --cert-name ドメイン名 --preferred-chain "DST Root CA X3"

dry-runで確認した後に実行。--cert-name でドメインの設定ファイルを指定する。

certbot renew --force-renew --cert-name ドメイン名 --preferred-chain "DST Root CA X3"

証明書は作り直さなくてもforce-renewalでOKぽい。

あくあーら@デブ鯖缶 (@aquarla@gochisou.dev) - ごちそうデブ

設定ファイルを見ると

preferred_chain = DST Root CA X3

が追記されていた。


設定を間違った場合の動作がまだ確認できないけれど、今はこれで良しとする。


crontabの設定は /usr/bin/certbot が存在しない(/snap/bin/certbot にある)し、systemdのタイマーには新しい版が登録されているのでcronは実行されないはず。ひとまず放置で。

テンプレートエンジンを使うのをやめたい

BladeOneをアップデートしたら、include時の変数割り当てのフローが変わったのか、既存変数が上書きされてエラーが出るようになってしまった。
本家Bladeではこういったことは起きない?
仕方がないのでバージョン固定した。

ソースを追っても何となく不毛なことになりそうなので、少しずつ外していくことを目指したい。
PHPの型が強化されてきたことだし、そろそろデータの受け渡しに配列や動的変数を使うことをやめたい。かなり減らしたけど、まだ@param mixedと書いている部分も多い。


素のPHPを使って、かつnamespaceを使って、型チェックもして、ビューからロジックはなるべく呼ばないようにして、などという設計に関する蓄積がない。
テンプレートエンジン無しっていうのは手を抜くためとか余計なものを入れないとかの理由が多かったように思う。


と思っていたのだけど
teratail.com
同じような人も居るには居るのか。

開発マシンの Debian stretch を buster にアップグレードする

GUIで使っていてOfficeやらGHCやら色々入っている。PHP5も入っている。
Dockerもsystemd-nspawnコンテナも入っている。
かなり躊躇していたが、そろそろアップグレードする。
サーバーで使っている Debian を buster にアップグレードしたログ - ログ日記
CUIなら問題なかったんだけど、どうなることやら。

まず、元に戻せるようにスナップショットを作成。
ホストからsshで入って作業する。

sources.list を busterに変更。独自に追加したリポジトリコメントアウト

apt update
apt-get upgrade

ファイル変更はNOで。

apt full-upgrade

削除されるパッケージのメモ
emacs25 php5-curl php7.0-curl php7.2-curl php7.3-curl php7.4-curl ruby-compass uim-qt uim-utils
libboost-*-1.62-dev default-java-plugin

アップグレード: 1072 個、新規インストール: 744 個、削除: 80 個、保留: 0 個。

あー、ここで /etc/apt/sources.list.d を見るのを忘れたことに気付いた。
結構 stretch 用の記述があるが…。自分で書いてないのでstretchとstableが混在しているな。
jessieもあるし、これどうしよう。

幸い(?)何故か403エラーで止まったので、手動で書き換えてから実行する。
sources.list.d のファイルをbusterに書き換えてエラーになったらコメントアウトする方針で。
buster-updates も取りあえずコメントアウト
それから今jpがダメっぽいので deb.debian.org に書き換えて再実行。
終わればclean。

apt autoremove

reboot

fc-cacheがエラーになったので再生成。

rm .cache/fontconfig/*
fc-cache -fv

emacs のフォントを再設定。*1

外観がちょっとおかしかったので外観の設定で選択し直す。
MATEのUIがわずかにリッチになって、ちょっともっさりしている気がする。
Alt+Tabの切り替えの表示が変わって分かりにくくなった。どこかに設定がある?
ターミナルの色がちょっと変になった。これもフォントやテーマがリセットされたからかな。



他に、特に大きな問題は無い模様。
emacsは25から26になってもフォントの設定を直せばそのまま使えた。
Eclipseもそのまま使える。
古いPHPや古いMySQLも使える。MySQLPostgreSQLはそれぞれ本家のリポジトリを追加しているから特に変更なし。PHPも独自リポジトリ。古いバージョンもそのまま。
Chrome Beta は枠が変な感じになった。MATEテーマのせい?
VS Code は使ってないけど起動はできた。
docker, kubernetes(使ってない), systemd-nspawn も異常なし。
systemdコンテナの中のOSも問題なく動いている。systemdのネットワーク設定を結構いじったけど、特に問題なし。
日本語入力もそのまま。
パッケージ指定がjessieになっていてコメントアウトしたslackも使えた。まあこれは普段はブラウザで使うけども。
パネルに追加したシステムモニターの負荷グラフの描写がちょっと変わったような。負荷が高く見える。

使えなくなったら困るアプリ gnucash も自動でデータ置き場が更新された模様。
LibreOfficeの起動画面がやたらカラフルになった。


動作確認はこれぐらいかな?
MATEの設定の細かい変更方法が分からん…。
「外観」メニュー以外に設定は無いんだろうか?
ググラビリティ低すぎるだろう…。

Alt + Tab でスイッチする操作中のウィンドウにマーカーが出て欲しいんだが。

もっさりしているのは「ウィンドウ」の「コンポジットマネージャー」をオフにすれば元に戻った。
あと、openboxの設定メニューがあるんだけど動いてないっぽい。何をどうやってインストールしたか忘れた。

ウィンドウの切り替えやテーマ、動きはLXDEが良いんだけど、パネルはMATEがいいんだよね。どうしよう。


※ 9/7 ひとまずMATEで使ってみてる。あとめっちゃtypoってた。

PHPStanのextensionでnamespace・class名の依存関係チェックする

前に書いた記事
DDDのさわりをやろうとした - ログ日記
ここで作ろうと思っていた拡張を作った。


github.com

サンプル。
https://github.com/nishimura/phpstan-namespace-dependency-sample


実際に作ってみると、各レイヤーごとの依存関係の認識が曖昧なことに気が付いた。

DomainはApplicationServceで生成するけど、生成したDomainのオブジェクトをそのまま返却しても良い?
ドメインのオブジェクトをそのまま返却してしまうと、Presentation層などでドメインの複雑な操作をしてしまえるので、Dtoに詰め替えてApplicationServiceResponse的なオブジェクトを返却すべきだった?
Javaなら例外を各層ごとにわざわざcatchして詰め替えてthrowするのが普通に見られるけど、PHPだとそこまではしないよね?
MVCのモデルをビューにそのまま渡して良い?簡略化したMVC2的なものは、ViewがModelに依存してしまっているよね?Modelのメソッドが変わったらViewに変更が必要だよね?
テンプレートで$entity->save() とかできるオブジェクトを扱うべきではないよね?
とか。


まあPHPだしそこまで細かくインターフェースを分離しなくていいかと思ってたことが色々とあぶり出された。

もっとちゃんと設計している人はこの辺をうまく整理して実装しているんだろうね。
自分は、最初は気を付けていてもいつの間にか忘れてメインのロジックが詰まったオブジェクトをテンプレートに渡したりしていた。
ある程度の規模までとかあまり複雑でない処理ならそっちの方が早いから、問題になることもなかった。

そんな省略したCRUDを早く作るための書き方に慣れている人でも、強制的にDDDできるツールになった。(のかどうかはこれから時間ができたら試す)

PHPの開発環境とライブラリと振り返りと近況

昔のコードを触る機会があった。
PHPの自作フレームワーク現状まとめ - ログ日記
この辺のやつ。
もう7年も前か…。

当時はテンプレートエンジンに変数を渡す場合、アクションコントローラーでメソッドを呼び出すのが流行っていた。

<?php
class MyController {
    public function index() {
        $this->set('foo', 1);
    }
}

<?php
class MyController {
    public function index() {
        $this->foo = 1;
    }
}

のような感じ。
どこでも変数を設定できるから作るときは楽なんだけど、コードが膨れてきたり後から見返すとあちこちでテンプレート変数が設定されていたりして大変だった。
それから、自分の作った機能なのに自動設定しすぎで結構忘れていた。

PHPのフレームワークを作った - ログ日記
@var でリクエスト変数のIDからDBアクセスして取得したオブジェクトをインジェクションするのはやりすぎだったかもわからん。
慣れると開発がめっちゃ早いんだけど。

$db->save($obj) で保存するのは楽だし、where(['col' => $value]) でSQL作るのも楽。
多少遅くてもいいならORMも便利だったなあと思い出してきた。

ただし、arrayや動的生成を多用していて型チェックされないのは不安だし、定義にジャンプできない部分が結構あった。
テンプレートエンジンの箇所でバグが出るのも若干不安。


それで忘れていた考え方の振り返り。
ぼんやり振り返り - ログ日記
この頃は、動的にコードを生成したり、流れるようなインターフェースにしようとしていたりしていた。
静的解析は使っていなかったし、コード補完もほとんど使ってなかった。書き方の問題もあって精度が低かったし。


その後、フルスクラッチの案件はあまりやらなくなって、WordPressとかEC-CUBEとかどこかの独自システムとかの修正等をやっていた。



そして最近、再びフルスクラッチでシステムを作った。
今見たらPHP 6万行、HTML 2万5千行、JavaScript 1万行あった。
PHPのテスト 8千行、CSS 1万行 も入れたら、10万行超えるね。
ここまでやったのは初めてかもしれない。

PHPのツールは
・自作フレームワーク
・自作ORM
・自作テンプレートエンジン
jQuery

から

・自作DIコンテナ PHPのDIコンテナを作った話 - Qiita
・FastRoute
・BladeOne
・Closure Library

に変えた。
速度重視の方針なので、基本ベタ書き。
フレームワークを使うと自動生成に頼っちゃうけど、手書きだとクラスを自分で書くことになる。
その代わりPHPStan のレベルMAXでチェックできて、クラスの定義もすぐ見れて安心感がある。
PHPStanに慣れてきてジェネリクスまで使えるとなると、今はBladeOneのテンプレートエンジンを外したくなってるところ。PHP側でめっちゃ細かく型チェックしてるのにテンプレートエンジンがザルだと意味ないじゃんっていう。

JavaScriptは速度重視なのでClosute Compiler、それならClosure Libraryだろうってことで。
PHPフルスタックは嫌だけど、JavaScriptはnpmの細かいライブラリの方が嫌だ。なので依存はClosure Toolsだけにする。
CSSもClosure Stylesheets。最終更新めっちゃ古いけど。

PHPは、FastRouteとDIコンテナとzend-diactoros とBladeOne、セッションライブラリ、Monologやちょっとしたツール系を繋げる薄いフレームワーク的なものを書いた。1000行いってないのでフレームワークというほどでもない。



開発環境は
・etags, gtags
PHPのモデル、コントローラー、HTML、CSSなどで分けてターミナルからEmacsを複数ウィンドウで立ち上げて並べる
・ローカルのApacheにバーチャルドメインで開発環境を設定、DBその他サービスもローカルにインストール
・GitLabから独自hook呼び出し

から

・gtags, ac-php
purpose-mode でウィンドウを複数立ち上げて並べる
systemd-nspawn で開発サーバーを用意
・GitLab CI

という感じに変わった。
あまり大きくは変わってないか。
Ansibleを使い始めたのが大きいかな。全体的に一周遅れてる感があるけど、KubernetesやDockerはオーバースペックなのでしゃーない。
DockerはCIのテストで使ってる。

サーバーは相変わらずさくらクラウドとさくらVPSコスパが良い。
大量アクセスをさばくのではなくて、1回のリクエストの応答を0.2秒以内にしたいとかいう方向の速度を出したいという要求がある。
個人的にも、最近のスマホ版Webは好きじゃない。細かくリクエストが分かれていてローディングアイコンがいつまでもクルクルしているし、もっさりしているし、スクロールが飛ぶし、リッチさにハードスペックが追いついてない感じがしている。
スケールアップで十分な規模のサイトをスケールアウトするのはナンセンスな感じもある。

あと、ネットショップばっかりやってるっていうのもあるかもね。
トランザクション大事。




そんな感じで最近はやっている。
でもさすがにSQLベタ書きは疲れてきたので、型チェック厳しめのORMを作りたいとか思っている。
関数呼び出しとオブジェクト生成って地味に処理時間取られるからあまり複雑なことはやりたくないんだけどね。管理者側の単純なCRUDならORMの方が開発コストが大幅に低くなるので、迷っている。
逆に、表側は長大なSQLを書いているのでORMは無理。

ひとまず次にやることは、テンプレートエンジンを外したり、コードを整理したり、テストを書いたりかなあ。
テストは金額計算と日付計算しかやってない。これで十分といえば十分だけども。

あとはE2Eテストか…。
何個か書いたけど、重いので増やしたくない方向に意識が傾いてしまう。
push時に実行するテストと毎日1回実行するテストを分ける、とかかなあ。


テンプレートエンジンを外すというのは、
型がある時代のPHP、テンプレートエンジンでも型チェックしたい - Qiita
こういうこと。
あと、これだとhtmlspecialcharsを忘れて危険なので
PHPStanで素のPHPをテンプレートとして使うとき、htmlspecialcharsをチェックする - Qiita
これもセットで。
少しずつやってる。